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