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 #ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_ACCESSIBILITY_MANAGER_H_ 6 #define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_ACCESSIBILITY_MANAGER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "base/callback_forward.h" 15 #include "base/callback_list.h" 16 #include "base/macros.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/scoped_observer.h" 19 #include "base/time/time.h" 20 #include "chrome/browser/chromeos/accessibility/chromevox_panel.h" 21 #include "chrome/browser/extensions/api/braille_display_private/braille_controller.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/profiles/profile_observer.h" 24 #include "chromeos/audio/cras_audio_handler.h" 25 #include "components/prefs/pref_change_registrar.h" 26 #include "components/user_manager/user_manager.h" 27 #include "content/public/browser/notification_observer.h" 28 #include "content/public/browser/notification_registrar.h" 29 #include "extensions/browser/event_router.h" 30 #include "extensions/browser/extension_registry.h" 31 #include "extensions/browser/extension_registry_observer.h" 32 #include "extensions/browser/extension_system.h" 33 #include "mojo/public/cpp/bindings/remote.h" 34 #include "services/media_session/public/mojom/audio_focus.mojom.h" 35 #include "ui/accessibility/ax_enums.mojom-forward.h" 36 #include "ui/base/ime/chromeos/input_method_manager.h" 37 38 class Browser; 39 40 namespace ash { 41 struct AccessibilityFocusRingInfo; 42 enum class SelectToSpeakState; 43 } // namespace ash 44 45 namespace gfx { 46 class Rect; 47 } // namespace gfx 48 49 namespace chromeos { 50 51 class AccessibilityExtensionLoader; 52 class DictationChromeos; 53 class SelectToSpeakEventHandlerDelegate; 54 55 enum AccessibilityNotificationType { 56 ACCESSIBILITY_MANAGER_SHUTDOWN, 57 ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE, 58 ACCESSIBILITY_TOGGLE_LARGE_CURSOR, 59 ACCESSIBILITY_TOGGLE_STICKY_KEYS, 60 ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER, 61 ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK, 62 ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK, 63 ACCESSIBILITY_TOGGLE_SWITCH_ACCESS, 64 ACCESSIBILITY_TOGGLE_VIRTUAL_KEYBOARD, 65 ACCESSIBILITY_TOGGLE_MONO_AUDIO, 66 ACCESSIBILITY_TOGGLE_CARET_HIGHLIGHT, 67 ACCESSIBILITY_TOGGLE_CURSOR_HIGHLIGHT, 68 ACCESSIBILITY_TOGGLE_FOCUS_HIGHLIGHT, 69 ACCESSIBILITY_TOGGLE_DICTATION, 70 ACCESSIBILITY_TOGGLE_DOCKED_MAGNIFIER, 71 }; 72 73 struct AccessibilityStatusEventDetails { 74 AccessibilityStatusEventDetails( 75 AccessibilityNotificationType notification_type, 76 bool enabled); 77 78 AccessibilityNotificationType notification_type; 79 bool enabled; 80 }; 81 82 using AccessibilityStatusCallbackList = 83 base::RepeatingCallbackList<void(const AccessibilityStatusEventDetails&)>; 84 using AccessibilityStatusCallback = 85 AccessibilityStatusCallbackList::CallbackType; 86 using AccessibilityStatusSubscription = 87 AccessibilityStatusCallbackList::Subscription; 88 89 class AccessibilityPanelWidgetObserver; 90 91 enum class PlaySoundOption { 92 // The sound is always played. 93 ALWAYS = 0, 94 95 // The sound is played only if spoken feedback is enabled, and 96 // --ash-disable-system-sounds is not set. 97 ONLY_IF_SPOKEN_FEEDBACK_ENABLED, 98 }; 99 100 // AccessibilityManager changes the statuses of accessibility features 101 // watching profile notifications and pref-changes. 102 // TODO(yoshiki): merge MagnificationManager with AccessibilityManager. 103 class AccessibilityManager 104 : public content::NotificationObserver, 105 public extensions::api::braille_display_private::BrailleObserver, 106 public extensions::ExtensionRegistryObserver, 107 public user_manager::UserManager::UserSessionStateObserver, 108 public input_method::InputMethodManager::Observer, 109 public CrasAudioHandler::AudioObserver, 110 public ProfileObserver { 111 public: 112 // Creates an instance of AccessibilityManager, this should be called once, 113 // because only one instance should exist at the same time. 114 static void Initialize(); 115 // Deletes the existing instance of AccessibilityManager. 116 static void Shutdown(); 117 // Returns the existing instance. If there is no instance, returns NULL. 118 static AccessibilityManager* Get(); 119 120 // Show the accessibility help as a tab in the browser. 121 static void ShowAccessibilityHelp(Browser* browser); 122 123 // Returns true when the accessibility menu should be shown. 124 bool ShouldShowAccessibilityMenu(); 125 126 // Enables or disables the large cursor. 127 void EnableLargeCursor(bool enabled); 128 129 // Returns true if the large cursor is enabled, or false if not. 130 bool IsLargeCursorEnabled() const; 131 132 // Enables or disable Sticky Keys. 133 void EnableStickyKeys(bool enabled); 134 135 // Returns true if the Sticky Keys is enabled, or false if not. 136 bool IsStickyKeysEnabled() const; 137 138 // Enables or disables spoken feedback. Enabling spoken feedback installs the 139 // ChromeVox component extension. 140 void EnableSpokenFeedback(bool enabled); 141 142 // Returns true if spoken feedback is enabled, or false if not. 143 bool IsSpokenFeedbackEnabled() const; 144 145 // Enables or disables the high contrast mode for Chrome. 146 void EnableHighContrast(bool enabled); 147 148 // Returns true if High Contrast is enabled, or false if not. 149 bool IsHighContrastEnabled() const; 150 151 // Enables or disables autoclick. 152 void EnableAutoclick(bool enabled); 153 154 // Returns true if autoclick is enabled. 155 bool IsAutoclickEnabled() const; 156 157 // Requests the Autoclick extension find the bounds of the nearest scrollable 158 // ancestor to the point in the screen, as given in screen coordinates. 159 void RequestAutoclickScrollableBoundsForPoint(gfx::Point& point_in_screen); 160 161 // Dispatches magnifier bounds update to Magnifier (through Accessibility 162 // Common extension). 163 void MagnifierBoundsChanged(const gfx::Rect& bounds_in_screen); 164 165 // Enables or disables the virtual keyboard. 166 void EnableVirtualKeyboard(bool enabled); 167 // Returns true if the virtual keyboard is enabled, otherwise false. 168 bool IsVirtualKeyboardEnabled() const; 169 170 // Enables or disables mono audio output. 171 void EnableMonoAudio(bool enabled); 172 // Returns true if mono audio output is enabled, otherwise false. 173 bool IsMonoAudioEnabled() const; 174 175 // Starts or stops darkening the screen. 176 void SetDarkenScreen(bool darken); 177 178 // Invoked to enable or disable caret highlighting. 179 void SetCaretHighlightEnabled(bool enabled); 180 181 // Returns if caret highlighting is enabled. 182 bool IsCaretHighlightEnabled() const; 183 184 // Invoked to enable or disable cursor highlighting. 185 void SetCursorHighlightEnabled(bool enabled); 186 187 // Returns if cursor highlighting is enabled. 188 bool IsCursorHighlightEnabled() const; 189 190 // Returns if dictation is enabled. 191 bool IsDictationEnabled() const; 192 193 // Invoked to enable or disable focus highlighting. 194 void SetFocusHighlightEnabled(bool enabled); 195 196 // Returns if focus highlighting is enabled. 197 bool IsFocusHighlightEnabled() const; 198 199 // Enables or disables tap dragging. 200 void EnableTapDragging(bool enabled); 201 202 // Returns true if the tap dragging is enabled, or false if not. 203 bool IsTapDraggingEnabled() const; 204 205 // Invoked to enable or disable select-to-speak. 206 void SetSelectToSpeakEnabled(bool enabled); 207 208 // Returns if select-to-speak is enabled. 209 bool IsSelectToSpeakEnabled() const; 210 211 // Requests that the Select-to-Speak extension change its state. 212 void RequestSelectToSpeakStateChange(); 213 214 // Called when the Select-to-Speak extension state has changed. 215 void SetSelectToSpeakState(ash::SelectToSpeakState state); 216 217 // Invoked to enable or disable Switch Access. 218 void SetSwitchAccessEnabled(bool enabled); 219 220 // Returns if Switch Access is enabled. 221 bool IsSwitchAccessEnabled() const; 222 223 // Returns true if a braille display is connected to the system, otherwise 224 // false. 225 bool IsBrailleDisplayConnected() const; 226 227 // user_manager::UserManager::UserSessionStateObserver overrides: 228 void ActiveUserChanged(user_manager::User* active_user) override; 229 230 // Initiates play of shutdown sound and returns it's duration. 231 base::TimeDelta PlayShutdownSound(); 232 233 // Register a callback to be notified when the status of an accessibility 234 // option changes. 235 std::unique_ptr<AccessibilityStatusSubscription> RegisterCallback( 236 const AccessibilityStatusCallback& cb) WARN_UNUSED_RESULT; 237 238 // Notify registered callbacks of a status change in an accessibility setting. 239 void NotifyAccessibilityStatusChanged( 240 const AccessibilityStatusEventDetails& details); 241 242 // Notify accessibility when locale changes occur. 243 void OnLocaleChanged(); 244 245 // Called when we first detect two fingers are held down, which can be 246 // used to toggle spoken feedback on some touch-only devices. 247 void OnTwoFingerTouchStart(); 248 249 // Called when the user is no longer holding down two fingers (including 250 // releasing one, holding down three, or moving them). 251 void OnTwoFingerTouchStop(); 252 253 // Whether or not to enable toggling spoken feedback via holding down 254 // two fingers on the screen. 255 bool ShouldToggleSpokenFeedbackViaTouch(); 256 257 // Play tick sound indicating spoken feedback will be toggled after countdown. 258 bool PlaySpokenFeedbackToggleCountdown(int tick_count); 259 260 // Update when a view is focused in ARC++. 261 void OnViewFocusedInArc(const gfx::Rect& bounds_in_screen, bool is_editable); 262 263 // Plays an earcon. Earcons are brief and distinctive sounds that indicate 264 // the their mapped event has occurred. The |sound_key| enums can be found in 265 // chromeos/audio/chromeos_sounds.h. 266 bool PlayEarcon(int sound_key, PlaySoundOption option); 267 268 // Forward an accessibility gesture from the touch exploration controller 269 // to ChromeVox. 270 void HandleAccessibilityGesture(ax::mojom::Gesture gesture, 271 gfx::PointF location); 272 273 // Update the touch exploration controller so that synthesized 274 // touch events are anchored at this point. 275 void SetTouchAccessibilityAnchorPoint(const gfx::Point& anchor_point); 276 277 // Called by our widget observer when the respective panel is closing. 278 void OnChromeVoxPanelDestroying(); 279 280 // Profile having the a11y context. profile()281 Profile* profile() { return profile_; } 282 283 // Extension id of extension receiving keyboard events. 284 void SetKeyboardListenerExtensionId(const std::string& id, 285 content::BrowserContext* context); keyboard_listener_extension_id()286 const std::string& keyboard_listener_extension_id() { 287 return keyboard_listener_extension_id_; 288 } 289 290 // Unloads Switch Access. 291 void OnSwitchAccessDisabled(); 292 293 // Starts or stops dictation (type what you speak). 294 bool ToggleDictation(); 295 296 // Sets the focus ring with the given ID based on |focus_ring|. 297 void SetFocusRing( 298 std::string focus_ring_id, 299 std::unique_ptr<ash::AccessibilityFocusRingInfo> focus_ring); 300 301 // Hides focus ring on screen. 302 void HideFocusRing(std::string caller_id); 303 304 // Initializes the focus rings when an extension loads. 305 void InitializeFocusRings(const std::string& extension_id); 306 307 // Hides all focus rings for the extension, and removes that extension from 308 // |focus_ring_names_for_extension_id_|. 309 void RemoveFocusRings(const std::string& extension_id); 310 311 // Draws a highlight at the given rects in screen coordinates. Rects may be 312 // overlapping and will be merged into one layer. This looks similar to 313 // selecting a region with the cursor, except it is drawn in the foreground 314 // rather than behind a text layer. 315 void SetHighlights(const std::vector<gfx::Rect>& rects_in_screen, 316 SkColor color); 317 318 // Hides highlight on screen. 319 void HideHighlights(); 320 321 // Sets the bounds used to highlight the text input caret. 322 void SetCaretBounds(const gfx::Rect& bounds_in_screen); 323 324 // Gets the startup sound user preference. 325 bool GetStartupSoundEnabled() const; 326 327 // Sets the startup sound user preference. 328 void SetStartupSoundEnabled(bool value) const; 329 330 // Gets the bluetooth braille display device address for the current user. 331 const std::string GetBluetoothBrailleDisplayAddress() const; 332 333 // Sets the bluetooth braille display device address for the current user. 334 void UpdateBluetoothBrailleDisplayAddress(const std::string& address); 335 336 // Create a focus ring ID from the extension ID and the name of the ring. 337 const std::string GetFocusRingId(const std::string& extension_id, 338 const std::string& focus_ring_name); 339 340 // Test helpers: 341 void SetProfileForTest(Profile* profile); 342 static void SetBrailleControllerForTest( 343 extensions::api::braille_display_private::BrailleController* controller); 344 void SetFocusRingObserverForTest(base::RepeatingCallback<void()> observer); 345 void SetSelectToSpeakStateObserverForTest( 346 base::RepeatingCallback<void()> observer); 347 void SetCaretBoundsObserverForTest( 348 base::RepeatingCallback<void(const gfx::Rect&)> observer); 349 void SetSwitchAccessKeysForTest(const std::vector<int>& keys); 350 GetAccessibilityCommonEnabledFeaturesForTest()351 const std::set<std::string>& GetAccessibilityCommonEnabledFeaturesForTest() { 352 return accessibility_common_enabled_features_; 353 } 354 355 protected: 356 AccessibilityManager(); 357 ~AccessibilityManager() override; 358 359 private: 360 void PostLoadChromeVox(); 361 void PostUnloadChromeVox(); 362 void PostSwitchChromeVoxProfile(); 363 364 void PostLoadSelectToSpeak(); 365 void PostUnloadSelectToSpeak(); 366 367 void PostLoadSwitchAccess(); 368 void PostUnloadSwitchAccess(); 369 370 void PostLoadAccessibilityCommon(); 371 void PostUnloadAccessibilityCommon(); 372 373 void UpdateAlwaysShowMenuFromPref(); 374 void OnLargeCursorChanged(); 375 void OnStickyKeysChanged(); 376 void OnSpokenFeedbackChanged(); 377 void OnHighContrastChanged(); 378 void OnVirtualKeyboardChanged(); 379 void OnMonoAudioChanged(); 380 void OnCaretHighlightChanged(); 381 void OnCursorHighlightChanged(); 382 void OnFocusHighlightChanged(); 383 void OnTapDraggingChanged(); 384 void OnSelectToSpeakChanged(); 385 void OnAccessibilityCommonChanged(const std::string& pref_name); 386 void OnSwitchAccessChanged(); 387 388 void CheckBrailleState(); 389 void ReceiveBrailleDisplayState( 390 std::unique_ptr<extensions::api::braille_display_private::DisplayState> 391 state); 392 void UpdateBrailleImeState(); 393 394 void SetProfile(Profile* profile); 395 396 void SetProfileByUser(const user_manager::User* user); 397 398 void UpdateChromeOSAccessibilityHistograms(); 399 400 void PlayVolumeAdjustSound(); 401 402 // content::NotificationObserver 403 void Observe(int type, 404 const content::NotificationSource& source, 405 const content::NotificationDetails& details) override; 406 407 // extensions::api::braille_display_private::BrailleObserver implementation. 408 // Enables spoken feedback if a braille display becomes available. 409 void OnBrailleDisplayStateChanged( 410 const extensions::api::braille_display_private::DisplayState& 411 display_state) override; 412 void OnBrailleKeyEvent( 413 const extensions::api::braille_display_private::KeyEvent& event) override; 414 415 // ExtensionRegistryObserver implementation. 416 void OnExtensionUnloaded(content::BrowserContext* browser_context, 417 const extensions::Extension* extension, 418 extensions::UnloadedExtensionReason reason) override; 419 void OnShutdown(extensions::ExtensionRegistry* registry) override; 420 421 // InputMethodManager::Observer 422 void InputMethodChanged(input_method::InputMethodManager* manager, 423 Profile* profile, 424 bool show_message) override; 425 426 // CrasAudioHandler::AudioObserver: 427 void OnActiveOutputNodeChanged() override; 428 429 // ProfileObserver: 430 void OnProfileWillBeDestroyed(Profile* profile) override; 431 432 // Profile which has the current a11y context. 433 Profile* profile_ = nullptr; 434 ScopedObserver<Profile, ProfileObserver> profile_observer_{this}; 435 436 content::NotificationRegistrar notification_registrar_; 437 std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; 438 std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_; 439 440 bool spoken_feedback_enabled_ = false; 441 bool select_to_speak_enabled_ = false; 442 bool switch_access_enabled_ = false; 443 444 // A set of pref names of enabled accessibility features using the 445 // accessibility common extension. 446 std::set<std::string> accessibility_common_enabled_features_; 447 448 AccessibilityStatusCallbackList callback_list_; 449 450 bool braille_display_connected_ = false; 451 ScopedObserver<extensions::api::braille_display_private::BrailleController, 452 extensions::api::braille_display_private::BrailleObserver> 453 scoped_braille_observer_{this}; 454 455 bool braille_ime_current_ = false; 456 457 ChromeVoxPanel* chromevox_panel_ = nullptr; 458 std::unique_ptr<AccessibilityPanelWidgetObserver> 459 chromevox_panel_widget_observer_; 460 461 std::string keyboard_listener_extension_id_; 462 bool keyboard_listener_capture_ = false; 463 464 // Listen to extension unloaded notifications. 465 ScopedObserver<extensions::ExtensionRegistry, 466 extensions::ExtensionRegistryObserver> 467 extension_registry_observer_{this}; 468 469 std::unique_ptr<AccessibilityExtensionLoader> 470 accessibility_common_extension_loader_; 471 472 std::unique_ptr<AccessibilityExtensionLoader> chromevox_loader_; 473 474 std::unique_ptr<AccessibilityExtensionLoader> select_to_speak_loader_; 475 476 std::unique_ptr<chromeos::SelectToSpeakEventHandlerDelegate> 477 select_to_speak_event_handler_delegate_; 478 479 std::unique_ptr<AccessibilityExtensionLoader> switch_access_loader_; 480 481 std::map<std::string, std::set<std::string>> 482 focus_ring_names_for_extension_id_; 483 484 bool app_terminating_ = false; 485 486 std::unique_ptr<DictationChromeos> dictation_; 487 488 base::RepeatingCallback<void()> focus_ring_observer_for_test_; 489 base::RepeatingCallback<void()> select_to_speak_state_observer_for_test_; 490 base::RepeatingCallback<void(const gfx::Rect&)> 491 caret_bounds_observer_for_test_; 492 493 // Used to set the audio focus enforcement type for ChromeVox. 494 mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_manager_; 495 496 // Whether the virtual keyboard was enabled before Switch Access loaded. 497 bool was_vk_enabled_before_switch_access_ = false; 498 499 base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_{this}; 500 501 friend class DictationTest; 502 friend class SwitchAccessTest; 503 504 DISALLOW_COPY_AND_ASSIGN(AccessibilityManager); 505 }; 506 507 } // namespace chromeos 508 509 #endif // CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_ACCESSIBILITY_MANAGER_H_ 510