blob: 263482da27c8286ca9bb7a3071daa348301dd5d0 [file] [log] [blame]
[email protected]1dfebfc2013-06-04 03:14:321// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
6
avi8a07d53892015-12-24 22:13:537#include <stddef.h>
8#include <stdint.h>
dcheng24002d02016-04-08 02:42:409
10#include <memory>
dcheng7c802f02015-12-31 16:09:5511#include <utility>
avi8a07d53892015-12-24 22:13:5312
msw61e16672016-08-12 16:36:5813#include "ash/aura/wm_window_aura.h"
pkotwicz04d5c892015-01-15 00:05:3614#include "ash/autoclick/autoclick_controller.h"
riajiang4b626b972016-09-13 16:12:4915#include "ash/autoclick/mus/public/interfaces/autoclick.mojom.h"
jamescook2b624c5a2016-06-08 01:34:0216#include "ash/common/session/session_state_delegate.h"
mswdf64c66b2016-08-23 18:56:3717#include "ash/common/shelf/shelf_layout_manager.h"
jamescook1cad77e92016-08-31 00:02:2618#include "ash/common/shelf/wm_shelf.h"
msw76014a32016-06-23 23:14:5719#include "ash/common/wm_shell.h"
pkotwicz04d5c892015-01-15 00:05:3620#include "ash/high_contrast/high_contrast_controller.h"
dmazzoniff86e3472016-06-03 19:52:3221#include "ash/root_window_controller.h"
pkotwicz04d5c892015-01-15 00:05:3622#include "ash/shell.h"
23#include "ash/sticky_keys/sticky_keys_controller.h"
[email protected]44beb032014-06-11 06:24:3724#include "base/callback.h"
25#include "base/callback_helpers.h"
plundbladcf1d08f2015-09-28 09:18:5826#include "base/command_line.h"
avi8a07d53892015-12-24 22:13:5327#include "base/macros.h"
fdorayba121422016-12-23 19:51:4828#include "base/memory/ptr_util.h"
[email protected]1dfebfc2013-06-04 03:14:3229#include "base/memory/singleton.h"
asvitkineb56637512016-09-01 19:41:4030#include "base/metrics/histogram_macros.h"
[email protected]ab38d192013-12-13 11:38:5831#include "base/path_service.h"
[email protected]2e5e0b12014-05-07 13:30:2032#include "base/strings/string_split.h"
33#include "base/strings/string_util.h"
[email protected]0b5a0d2b2013-10-30 03:43:4034#include "base/time/time.h"
[email protected]0aae2fe2013-07-05 07:04:4235#include "base/values.h"
[email protected]1dfebfc2013-06-04 03:14:3236#include "chrome/browser/accessibility/accessibility_extension_api.h"
37#include "chrome/browser/browser_process.h"
[email protected]fdf40f3e2013-07-11 23:55:4638#include "chrome/browser/chrome_notification_types.h"
dmazzoni337c5af2016-09-13 23:08:5739#include "chrome/browser/chromeos/accessibility/accessibility_extension_loader.h"
dmazzonib93107c2016-03-22 21:51:1840#include "chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h"
pkotwicz04d5c892015-01-15 00:05:3641#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
dmazzoni735c79df2016-11-28 22:39:4242#include "chrome/browser/chromeos/accessibility/select_to_speak_event_handler.h"
dmazzoni16d2dec2016-12-19 23:27:5743#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
44#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
[email protected]e6f20642013-06-11 17:05:4645#include "chrome/browser/chromeos/profiles/profile_helper.h"
dmazzonifb33d592014-10-30 19:26:5446#include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h"
plundbladcf1d08f2015-09-28 09:18:5847#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
[email protected]1dfebfc2013-06-04 03:14:3248#include "chrome/browser/extensions/extension_service.h"
gogeralddde4ee02015-08-26 18:58:4949#include "chrome/browser/prefs/incognito_mode_prefs.h"
[email protected]1dfebfc2013-06-04 03:14:3250#include "chrome/browser/profiles/profile.h"
51#include "chrome/browser/profiles/profile_manager.h"
riajiang4b626b972016-09-13 16:12:4952#include "chrome/browser/ui/ash/ash_util.h"
[email protected]ab38d192013-12-13 11:38:5853#include "chrome/common/chrome_paths.h"
[email protected]9848bf6c2014-05-09 12:34:0054#include "chrome/common/extensions/api/accessibility_private.h"
[email protected]dccba4f82014-05-29 00:52:5655#include "chrome/common/extensions/extension_constants.h"
[email protected]1dfebfc2013-06-04 03:14:3256#include "chrome/common/pref_names.h"
[email protected]b58d2f82014-08-09 05:36:1457#include "chrome/grit/browser_resources.h"
warx533c8f62016-04-12 01:19:4358#include "chromeos/audio/audio_a11y_controller.h"
[email protected]ce89d9392013-12-11 21:05:2059#include "chromeos/audio/chromeos_sounds.h"
[email protected]0aae2fe2013-07-05 07:04:4260#include "chromeos/login/login_state.h"
brettwb1fc1b82016-02-02 00:19:0861#include "components/prefs/pref_member.h"
62#include "components/prefs/pref_service.h"
[email protected]4d390782014-08-15 09:22:5863#include "components/user_manager/user_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3264#include "content/public/browser/browser_accessibility_state.h"
[email protected]8c79e3f2013-10-30 01:05:1465#include "content/public/browser/browser_thread.h"
[email protected]9cf54f362013-07-01 07:28:1266#include "content/public/browser/notification_details.h"
[email protected]1dfebfc2013-06-04 03:14:3267#include "content/public/browser/notification_service.h"
[email protected]9cf54f362013-07-01 07:28:1268#include "content/public/browser/notification_source.h"
[email protected]1dfebfc2013-06-04 03:14:3269#include "content/public/browser/render_view_host.h"
[email protected]1dfebfc2013-06-04 03:14:3270#include "content/public/browser/web_ui.h"
plundbladcf1d08f2015-09-28 09:18:5871#include "content/public/common/content_switches.h"
bend32292b2016-10-07 00:21:5872#include "content/public/common/service_manager_connection.h"
juncaicf523332015-06-04 00:14:0473#include "extensions/browser/event_router.h"
reillyga3acbc12014-11-11 23:17:1274#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2475#include "extensions/browser/extension_system.h"
[email protected]e4452d32013-11-15 23:07:4176#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0877#include "extensions/common/extension_messages.h"
[email protected]1dfebfc2013-06-04 03:14:3278#include "extensions/common/extension_resource.h"
hanxi79f7a572015-03-09 20:46:5979#include "extensions/common/host_id.h"
riajiang4b626b972016-09-13 16:12:4980#include "mash/public/interfaces/launchable.mojom.h"
[email protected]12b0a842013-12-04 20:48:1381#include "media/audio/sounds/sounds_manager.h"
dtsengd50debe32016-12-29 06:23:3782#include "media/base/media_switches.h"
rockot734fb662016-10-15 16:41:3083#include "services/service_manager/public/cpp/connector.h"
shuchen179b1f42014-11-27 17:24:4084#include "ui/base/ime/chromeos/input_method_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3285#include "ui/base/resource/resource_bundle.h"
[email protected]e1b299b2014-01-29 23:53:4186#include "ui/keyboard/keyboard_controller.h"
87#include "ui/keyboard/keyboard_util.h"
[email protected]1dfebfc2013-06-04 03:14:3288
[email protected]8c79e3f2013-10-30 01:05:1489using content::BrowserThread;
[email protected]1dfebfc2013-06-04 03:14:3290using content::RenderViewHost;
[email protected]8c79e3f2013-10-30 01:05:1491using extensions::api::braille_display_private::BrailleController;
92using extensions::api::braille_display_private::DisplayState;
[email protected]2e5e0b12014-05-07 13:30:2093using extensions::api::braille_display_private::KeyEvent;
plundbladcf1d08f2015-09-28 09:18:5894using extensions::api::braille_display_private::StubBrailleController;
[email protected]1dfebfc2013-06-04 03:14:3295
96namespace chromeos {
97
98namespace {
99
sadrulcdc2bb42016-07-13 19:44:51100// When this flag is set, system sounds will not be played.
101const char kAshDisableSystemSounds[] = "ash-disable-system-sounds";
102
103// When this flag is set, system sounds will be played whether the
104// ChromeVox is enabled or not.
105const char kAshEnableSystemSounds[] = "ash-enable-system-sounds";
106
[email protected]1dfebfc2013-06-04 03:14:32107static chromeos::AccessibilityManager* g_accessibility_manager = NULL;
108
[email protected]8c79e3f2013-10-30 01:05:14109static BrailleController* g_braille_controller_for_test = NULL;
110
111BrailleController* GetBrailleController() {
plundbladcf1d08f2015-09-28 09:18:58112 if (g_braille_controller_for_test)
113 return g_braille_controller_for_test;
114 // Don't use the real braille controller for tests to avoid automatically
115 // starting ChromeVox which confuses some tests.
116 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
117 if (command_line->HasSwitch(switches::kTestType))
118 return StubBrailleController::GetInstance();
119 return BrailleController::GetInstance();
[email protected]8c79e3f2013-10-30 01:05:14120}
121
[email protected]1dfebfc2013-06-04 03:14:32122} // namespace
123
dmazzoni94a4f882015-11-13 05:46:52124class ChromeVoxPanelWidgetObserver : public views::WidgetObserver {
125 public:
126 ChromeVoxPanelWidgetObserver(views::Widget* widget,
127 AccessibilityManager* manager)
128 : widget_(widget), manager_(manager) {
129 widget_->AddObserver(this);
130 }
131
132 void OnWidgetClosing(views::Widget* widget) override {
133 CHECK_EQ(widget_, widget);
134 widget->RemoveObserver(this);
135 manager_->OnChromeVoxPanelClosing();
136 }
137
138 void OnWidgetDestroying(views::Widget* widget) override {
139 CHECK_EQ(widget_, widget);
140 widget->RemoveObserver(this);
141 manager_->OnChromeVoxPanelDestroying();
142 }
143
144 private:
145 views::Widget* widget_;
146 AccessibilityManager* manager_;
147
148 DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWidgetObserver);
149};
150
[email protected]1dfebfc2013-06-04 03:14:32151///////////////////////////////////////////////////////////////////////////////
152// AccessibilityStatusEventDetails
153
154AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03155 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32156 bool enabled,
jamescooka7f8dab2016-06-21 01:44:03157 ash::AccessibilityNotificationVisibility notify)
158 : notification_type(notification_type),
159 enabled(enabled),
160 magnifier_type(ash::kDefaultMagnifierType),
161 notify(notify) {}
[email protected]1dfebfc2013-06-04 03:14:32162
163AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03164 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32165 bool enabled,
jamescooka7f8dab2016-06-21 01:44:03166 ash::MagnifierType magnifier_type,
167 ash::AccessibilityNotificationVisibility notify)
168 : notification_type(notification_type),
169 enabled(enabled),
170 magnifier_type(magnifier_type),
171 notify(notify) {}
[email protected]1dfebfc2013-06-04 03:14:32172
173///////////////////////////////////////////////////////////////////////////////
174//
[email protected]0aae2fe2013-07-05 07:04:42175// AccessibilityManager::PrefHandler
176
177AccessibilityManager::PrefHandler::PrefHandler(const char* pref_path)
178 : pref_path_(pref_path) {}
179
180AccessibilityManager::PrefHandler::~PrefHandler() {}
181
182void AccessibilityManager::PrefHandler::HandleProfileChanged(
183 Profile* previous_profile, Profile* current_profile) {
184 // Returns if the current profile is null.
185 if (!current_profile)
186 return;
187
188 // If the user set a pref value on the login screen and is now starting a
189 // session with a new profile, copy the pref value to the profile.
190 if ((previous_profile &&
191 ProfileHelper::IsSigninProfile(previous_profile) &&
192 current_profile->IsNewProfile() &&
193 !ProfileHelper::IsSigninProfile(current_profile)) ||
194 // Special case for Guest mode:
195 // Guest mode launches a guest-mode browser process before session starts,
196 // so the previous profile is null.
197 (!previous_profile &&
198 current_profile->IsGuestSession())) {
199 // Returns if the pref has not been set by the user.
200 const PrefService::Preference* pref = ProfileHelper::GetSigninProfile()->
201 GetPrefs()->FindPreference(pref_path_);
202 if (!pref || !pref->IsUserControlled())
203 return;
204
205 // Copy the pref value from the signin screen.
206 const base::Value* value_on_login = pref->GetValue();
207 PrefService* user_prefs = current_profile->GetPrefs();
208 user_prefs->Set(pref_path_, *value_on_login);
209 }
210}
211
212///////////////////////////////////////////////////////////////////////////////
213//
[email protected]1dfebfc2013-06-04 03:14:32214// AccessibilityManager
215
216// static
217void AccessibilityManager::Initialize() {
218 CHECK(g_accessibility_manager == NULL);
219 g_accessibility_manager = new AccessibilityManager();
220}
221
222// static
223void AccessibilityManager::Shutdown() {
224 CHECK(g_accessibility_manager);
225 delete g_accessibility_manager;
226 g_accessibility_manager = NULL;
227}
228
229// static
230AccessibilityManager* AccessibilityManager::Get() {
231 return g_accessibility_manager;
232}
233
[email protected]d80f19302013-06-07 13:12:14234AccessibilityManager::AccessibilityManager()
235 : profile_(NULL),
[email protected]ced247a2014-06-13 19:14:19236 large_cursor_pref_handler_(prefs::kAccessibilityLargeCursorEnabled),
237 spoken_feedback_pref_handler_(prefs::kAccessibilitySpokenFeedbackEnabled),
238 high_contrast_pref_handler_(prefs::kAccessibilityHighContrastEnabled),
239 autoclick_pref_handler_(prefs::kAccessibilityAutoclickEnabled),
240 autoclick_delay_pref_handler_(prefs::kAccessibilityAutoclickDelayMs),
241 virtual_keyboard_pref_handler_(
242 prefs::kAccessibilityVirtualKeyboardEnabled),
jamescooka7f8dab2016-06-21 01:44:03243 mono_audio_pref_handler_(prefs::kAccessibilityMonoAudioEnabled),
dmazzoni756089a22016-03-15 23:55:16244 caret_highlight_pref_handler_(prefs::kAccessibilityCaretHighlightEnabled),
245 cursor_highlight_pref_handler_(
246 prefs::kAccessibilityCursorHighlightEnabled),
247 focus_highlight_pref_handler_(prefs::kAccessibilityFocusHighlightEnabled),
248 select_to_speak_pref_handler_(prefs::kAccessibilitySelectToSpeakEnabled),
249 switch_access_pref_handler_(prefs::kAccessibilitySwitchAccessEnabled),
[email protected]d80f19302013-06-07 13:12:14250 large_cursor_enabled_(false),
[email protected]93a534e2013-06-20 16:41:44251 sticky_keys_enabled_(false),
[email protected]d80f19302013-06-07 13:12:14252 spoken_feedback_enabled_(false),
253 high_contrast_enabled_(false),
[email protected]186ba06bc2013-11-26 18:02:19254 autoclick_enabled_(false),
sammiequon820646f2016-06-24 18:47:13255 autoclick_delay_ms_(ash::AutoclickController::GetDefaultAutoclickDelay()),
[email protected]e1b299b2014-01-29 23:53:41256 virtual_keyboard_enabled_(false),
warx533c8f62016-04-12 01:19:43257 mono_audio_enabled_(false),
dmazzoni756089a22016-03-15 23:55:16258 caret_highlight_enabled_(false),
259 cursor_highlight_enabled_(false),
260 focus_highlight_enabled_(false),
261 select_to_speak_enabled_(false),
262 switch_access_enabled_(false),
jamescooka7f8dab2016-06-21 01:44:03263 spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE),
[email protected]ce89d9392013-12-11 21:05:20264 should_speak_chrome_vox_announcements_on_user_screen_(true),
[email protected]a81b2c32014-03-28 06:35:01265 system_sounds_enabled_(false),
266 braille_display_connected_(false),
[email protected]2e5e0b12014-05-07 13:30:20267 scoped_braille_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51268 braille_ime_current_(false),
dmazzoni94a4f882015-11-13 05:46:52269 chromevox_panel_(nullptr),
dtsengfb6d7cd2016-01-20 23:00:13270 extension_registry_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51271 weak_ptr_factory_(this) {
[email protected]1dfebfc2013-06-04 03:14:32272 notification_registrar_.Add(this,
[email protected]093d9ba2013-07-23 19:26:21273 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
[email protected]e6f20642013-06-11 17:05:46274 content::NotificationService::AllSources());
275 notification_registrar_.Add(this,
[email protected]1dfebfc2013-06-04 03:14:32276 chrome::NOTIFICATION_SESSION_STARTED,
277 content::NotificationService::AllSources());
278 notification_registrar_.Add(this,
[email protected]1dfebfc2013-06-04 03:14:32279 chrome::NOTIFICATION_PROFILE_DESTROYED,
280 content::NotificationService::AllSources());
[email protected]b0a2ce32013-07-23 15:24:53281 notification_registrar_.Add(this,
282 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
283 content::NotificationService::AllSources());
[email protected]c20122572013-12-16 20:35:58284
[email protected]1488a035f2014-03-28 21:12:07285 input_method::InputMethodManager::Get()->AddObserver(this);
286
[email protected]12b0a842013-12-04 20:48:13287 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
[email protected]ce89d9392013-12-11 21:05:20288 media::SoundsManager* manager = media::SoundsManager::Get();
289 manager->Initialize(SOUND_SHUTDOWN,
290 bundle.GetRawDataResource(IDR_SOUND_SHUTDOWN_WAV));
291 manager->Initialize(
292 SOUND_SPOKEN_FEEDBACK_ENABLED,
293 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_ENABLED_WAV));
294 manager->Initialize(
295 SOUND_SPOKEN_FEEDBACK_DISABLED,
296 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_DISABLED_WAV));
[email protected]07f3ea92014-08-14 05:23:38297 manager->Initialize(SOUND_PASSTHROUGH,
298 bundle.GetRawDataResource(IDR_SOUND_PASSTHROUGH_WAV));
299 manager->Initialize(SOUND_EXIT_SCREEN,
300 bundle.GetRawDataResource(IDR_SOUND_EXIT_SCREEN_WAV));
301 manager->Initialize(SOUND_ENTER_SCREEN,
302 bundle.GetRawDataResource(IDR_SOUND_ENTER_SCREEN_WAV));
dmazzoni16d2dec2016-12-19 23:27:57303 manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH,
304 bundle.GetRawDataResource(
305 IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH_WAV));
306 manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
307 bundle.GetRawDataResource(
308 IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV));
dmazzoni337c5af2016-09-13 23:08:57309
310 base::FilePath resources_path;
311 if (!PathService::Get(chrome::DIR_RESOURCES, &resources_path))
312 NOTREACHED();
313 chromevox_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
314 extension_misc::kChromeVoxExtensionId,
315 resources_path.Append(extension_misc::kChromeVoxExtensionPath),
316 base::Bind(&AccessibilityManager::PostUnloadChromeVox,
317 weak_ptr_factory_.GetWeakPtr())));
dmazzoni5288b2612016-09-16 23:05:39318 select_to_speak_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
319 extension_misc::kSelectToSpeakExtensionId,
320 resources_path.Append(extension_misc::kSelectToSpeakExtensionPath),
321 base::Closure()));
[email protected]1dfebfc2013-06-04 03:14:32322}
323
324AccessibilityManager::~AccessibilityManager() {
325 CHECK(this == g_accessibility_manager);
jamescooka7f8dab2016-06-21 01:44:03326 AccessibilityStatusEventDetails details(ACCESSIBILITY_MANAGER_SHUTDOWN, false,
327 ash::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03328 NotifyAccessibilityStatusChanged(details);
[email protected]1488a035f2014-03-28 21:12:07329 input_method::InputMethodManager::Get()->RemoveObserver(this);
dmazzoni94a4f882015-11-13 05:46:52330
331 if (chromevox_panel_) {
332 chromevox_panel_->Close();
333 chromevox_panel_ = nullptr;
334 }
[email protected]1dfebfc2013-06-04 03:14:32335}
336
[email protected]c20122572013-12-16 20:35:58337bool AccessibilityManager::ShouldShowAccessibilityMenu() {
338 // If any of the loaded profiles has an accessibility feature turned on - or
339 // enforced to always show the menu - we return true to show the menu.
340 std::vector<Profile*> profiles =
341 g_browser_process->profile_manager()->GetLoadedProfiles();
342 for (std::vector<Profile*>::iterator it = profiles.begin();
343 it != profiles.end();
344 ++it) {
345 PrefService* pref_service = (*it)->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19346 if (pref_service->GetBoolean(prefs::kAccessibilityStickyKeysEnabled) ||
347 pref_service->GetBoolean(prefs::kAccessibilityLargeCursorEnabled) ||
348 pref_service->GetBoolean(prefs::kAccessibilitySpokenFeedbackEnabled) ||
349 pref_service->GetBoolean(prefs::kAccessibilityHighContrastEnabled) ||
350 pref_service->GetBoolean(prefs::kAccessibilityAutoclickEnabled) ||
[email protected]c20122572013-12-16 20:35:58351 pref_service->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu) ||
[email protected]ced247a2014-06-13 19:14:19352 pref_service->GetBoolean(prefs::kAccessibilityScreenMagnifierEnabled) ||
warx533c8f62016-04-12 01:19:43353 pref_service->GetBoolean(prefs::kAccessibilityVirtualKeyboardEnabled) ||
354 pref_service->GetBoolean(prefs::kAccessibilityMonoAudioEnabled))
[email protected]c20122572013-12-16 20:35:58355 return true;
356 }
357 return false;
358}
359
[email protected]a4994f1e2014-02-11 18:58:16360bool AccessibilityManager::ShouldEnableCursorCompositing() {
[email protected]f74c0b9c2014-04-17 23:24:03361 if (!profile_)
362 return false;
363 PrefService* pref_service = profile_->GetPrefs();
364 // Enable cursor compositing when one or more of the listed accessibility
365 // features are turned on.
[email protected]ced247a2014-06-13 19:14:19366 if (pref_service->GetBoolean(prefs::kAccessibilityLargeCursorEnabled) ||
367 pref_service->GetBoolean(prefs::kAccessibilityHighContrastEnabled) ||
368 pref_service->GetBoolean(prefs::kAccessibilityScreenMagnifierEnabled))
[email protected]f74c0b9c2014-04-17 23:24:03369 return true;
[email protected]a4994f1e2014-02-11 18:58:16370 return false;
371}
372
[email protected]8126b812013-06-06 03:49:17373void AccessibilityManager::EnableLargeCursor(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14374 if (!profile_)
375 return;
376
377 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19378 pref_service->SetBoolean(prefs::kAccessibilityLargeCursorEnabled, enabled);
[email protected]d80f19302013-06-07 13:12:14379 pref_service->CommitPendingWrite();
380}
381
382void AccessibilityManager::UpdateLargeCursorFromPref() {
383 if (!profile_)
384 return;
385
386 const bool enabled =
[email protected]ced247a2014-06-13 19:14:19387 profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityLargeCursorEnabled);
[email protected]d80f19302013-06-07 13:12:14388
[email protected]8126b812013-06-06 03:49:17389 if (large_cursor_enabled_ == enabled)
390 return;
391
392 large_cursor_enabled_ = enabled;
393
jamescooka7f8dab2016-06-21 01:44:03394 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_LARGE_CURSOR,
395 enabled, ash::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03396
397 NotifyAccessibilityStatusChanged(details);
[email protected]846be6e2013-06-07 08:03:26398
[email protected]a7c93e32013-09-03 08:50:30399 ash::Shell::GetInstance()->cursor_manager()->SetCursorSet(
400 enabled ? ui::CURSOR_SET_LARGE : ui::CURSOR_SET_NORMAL);
[email protected]87ec2202014-02-06 06:24:27401 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
[email protected]a4994f1e2014-02-11 18:58:16402 ShouldEnableCursorCompositing());
[email protected]8126b812013-06-06 03:49:17403}
404
[email protected]5ecf6122013-10-31 12:24:09405bool AccessibilityManager::IsIncognitoAllowed() {
gogeralddde4ee02015-08-26 18:58:49406 return profile_ != NULL &&
407 profile_->GetProfileType() != Profile::GUEST_PROFILE &&
408 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) !=
409 IncognitoModePrefs::DISABLED;
[email protected]5ecf6122013-10-31 12:24:09410}
411
[email protected]8126b812013-06-06 03:49:17412bool AccessibilityManager::IsLargeCursorEnabled() {
413 return large_cursor_enabled_;
414}
415
[email protected]93a534e2013-06-20 16:41:44416void AccessibilityManager::EnableStickyKeys(bool enabled) {
417 if (!profile_)
418 return;
419 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19420 pref_service->SetBoolean(prefs::kAccessibilityStickyKeysEnabled, enabled);
[email protected]93a534e2013-06-20 16:41:44421 pref_service->CommitPendingWrite();
422}
423
424bool AccessibilityManager::IsStickyKeysEnabled() {
425 return sticky_keys_enabled_;
426}
427
428void AccessibilityManager::UpdateStickyKeysFromPref() {
429 if (!profile_)
430 return;
431
432 const bool enabled =
[email protected]ced247a2014-06-13 19:14:19433 profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityStickyKeysEnabled);
[email protected]93a534e2013-06-20 16:41:44434
435 if (sticky_keys_enabled_ == enabled)
436 return;
437
438 sticky_keys_enabled_ = enabled;
[email protected]08bdabed2013-12-20 07:52:28439 ash::Shell::GetInstance()->sticky_keys_controller()->Enable(enabled);
[email protected]93a534e2013-06-20 16:41:44440}
441
[email protected]1dfebfc2013-06-04 03:14:32442void AccessibilityManager::EnableSpokenFeedback(
443 bool enabled,
jamescooka7f8dab2016-06-21 01:44:03444 ash::AccessibilityNotificationVisibility notify) {
[email protected]1dfebfc2013-06-04 03:14:32445 if (!profile_)
446 return;
msw76014a32016-06-23 23:14:57447 ash::WmShell::Get()->RecordUserMetricsAction(
[email protected]5d2ea362013-12-13 08:10:18448 enabled ? ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK
449 : ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK);
450
[email protected]d80f19302013-06-07 13:12:14451 spoken_feedback_notification_ = notify;
452
[email protected]1dfebfc2013-06-04 03:14:32453 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19454 pref_service->SetBoolean(prefs::kAccessibilitySpokenFeedbackEnabled, enabled);
[email protected]1dfebfc2013-06-04 03:14:32455 pref_service->CommitPendingWrite();
[email protected]d80f19302013-06-07 13:12:14456
jamescooka7f8dab2016-06-21 01:44:03457 spoken_feedback_notification_ = ash::A11Y_NOTIFICATION_NONE;
[email protected]d80f19302013-06-07 13:12:14458}
459
460void AccessibilityManager::UpdateSpokenFeedbackFromPref() {
461 if (!profile_)
462 return;
463
[email protected]ced247a2014-06-13 19:14:19464 const bool enabled = profile_->GetPrefs()->GetBoolean(
465 prefs::kAccessibilitySpokenFeedbackEnabled);
[email protected]d80f19302013-06-07 13:12:14466
dmazzoni63199b12016-10-19 15:44:36467 if (enabled) {
468 chromevox_loader_->SetProfile(
469 profile_, base::Bind(&AccessibilityManager::PostSwitchChromeVoxProfile,
470 weak_ptr_factory_.GetWeakPtr()));
471 }
dmazzoni2c013202016-09-07 19:59:37472
[email protected]d80f19302013-06-07 13:12:14473 if (spoken_feedback_enabled_ == enabled)
474 return;
475
476 spoken_feedback_enabled_ = enabled;
477
[email protected]d8edc9c2014-02-25 00:06:03478 AccessibilityStatusEventDetails details(
479 ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
480 enabled,
481 spoken_feedback_notification_);
482
483 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32484
[email protected]0e9504d2013-11-05 02:33:29485 if (enabled) {
dmazzoni337c5af2016-09-13 23:08:57486 chromevox_loader_->Load(profile_, "window.INJECTED_AFTER_LOAD = true;",
487 base::Bind(&AccessibilityManager::PostLoadChromeVox,
488 weak_ptr_factory_.GetWeakPtr()));
[email protected]0e9504d2013-11-05 02:33:29489 } else {
dmazzoni337c5af2016-09-13 23:08:57490 chromevox_loader_->Unload();
[email protected]0e9504d2013-11-05 02:33:29491 }
[email protected]2e5e0b12014-05-07 13:30:20492 UpdateBrailleImeState();
dmazzoni1970d4e62016-06-16 23:46:34493
494 // ChromeVox focus highlighting overrides the other focus highlighting.
495 UpdateFocusHighlightFromPref();
[email protected]b0a2ce32013-07-23 15:24:53496}
497
[email protected]1dfebfc2013-06-04 03:14:32498bool AccessibilityManager::IsSpokenFeedbackEnabled() {
499 return spoken_feedback_enabled_;
500}
501
502void AccessibilityManager::ToggleSpokenFeedback(
jamescooka7f8dab2016-06-21 01:44:03503 ash::AccessibilityNotificationVisibility notify) {
[email protected]681d0532013-06-11 12:52:50504 EnableSpokenFeedback(!IsSpokenFeedbackEnabled(), notify);
[email protected]1dfebfc2013-06-04 03:14:32505}
506
[email protected]1dfebfc2013-06-04 03:14:32507void AccessibilityManager::EnableHighContrast(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14508 if (!profile_)
509 return;
510
511 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19512 pref_service->SetBoolean(prefs::kAccessibilityHighContrastEnabled, enabled);
[email protected]d80f19302013-06-07 13:12:14513 pref_service->CommitPendingWrite();
514}
515
516void AccessibilityManager::UpdateHighContrastFromPref() {
517 if (!profile_)
518 return;
519
[email protected]ced247a2014-06-13 19:14:19520 const bool enabled = profile_->GetPrefs()->GetBoolean(
521 prefs::kAccessibilityHighContrastEnabled);
[email protected]d80f19302013-06-07 13:12:14522
[email protected]1dfebfc2013-06-04 03:14:32523 if (high_contrast_enabled_ == enabled)
524 return;
525
526 high_contrast_enabled_ = enabled;
527
[email protected]d8edc9c2014-02-25 00:06:03528 AccessibilityStatusEventDetails details(
jamescooka7f8dab2016-06-21 01:44:03529 ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE, enabled,
530 ash::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03531
532 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32533
[email protected]1dfebfc2013-06-04 03:14:32534 ash::Shell::GetInstance()->high_contrast_controller()->SetEnabled(enabled);
[email protected]87ec2202014-02-06 06:24:27535 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
[email protected]a4994f1e2014-02-11 18:58:16536 ShouldEnableCursorCompositing());
[email protected]1dfebfc2013-06-04 03:14:32537}
538
[email protected]628b8902014-03-12 05:26:41539void AccessibilityManager::OnLocaleChanged() {
[email protected]d1d5f4f2013-06-14 07:17:09540 if (!profile_)
541 return;
542
543 if (!IsSpokenFeedbackEnabled())
544 return;
545
546 // If the system locale changes and spoken feedback is enabled,
547 // reload ChromeVox so that it switches its internal translations
548 // to the new language.
jamescooka7f8dab2016-06-21 01:44:03549 EnableSpokenFeedback(false, ash::A11Y_NOTIFICATION_NONE);
550 EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_NONE);
[email protected]d1d5f4f2013-06-14 07:17:09551}
552
sadrulcdc2bb42016-07-13 19:44:51553bool AccessibilityManager::PlayEarcon(int sound_key, PlaySoundOption option) {
[email protected]07f3ea92014-08-14 05:23:38554 DCHECK(sound_key < chromeos::SOUND_COUNT);
sadrulcdc2bb42016-07-13 19:44:51555 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
556 if (cl->HasSwitch(kAshDisableSystemSounds))
557 return false;
558 if (option == PlaySoundOption::SPOKEN_FEEDBACK_ENABLED &&
559 !IsSpokenFeedbackEnabled() && !cl->HasSwitch(kAshEnableSystemSounds)) {
560 return false;
561 }
562 return media::SoundsManager::Get()->Play(sound_key);
[email protected]07f3ea92014-08-14 05:23:38563}
564
dmazzoni16d2dec2016-12-19 23:27:57565bool AccessibilityManager::ShouldToggleSpokenFeedbackViaTouch() {
566 policy::BrowserPolicyConnectorChromeOS* connector =
567 g_browser_process->platform_part()->browser_policy_connector_chromeos();
568 if (!connector)
569 return false;
570
571 if (!connector->IsEnterpriseManaged())
572 return false;
573
574 const policy::DeviceCloudPolicyManagerChromeOS* const
575 device_cloud_policy_manager = connector->GetDeviceCloudPolicyManager();
576 if (!device_cloud_policy_manager)
577 return false;
578
579 if (!device_cloud_policy_manager->IsRemoraRequisition())
580 return false;
581
582 KioskAppManager* manager = KioskAppManager::Get();
583 KioskAppManager::App app;
584 CHECK(manager->GetApp(manager->GetAutoLaunchApp(), &app));
585 return app.was_auto_launched_with_zero_delay;
586}
587
588bool AccessibilityManager::PlaySpokenFeedbackToggleCountdown(int tick_count) {
589 return media::SoundsManager::Get()->Play(
590 tick_count % 2 ? SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH
591 : SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW);
592}
593
dmazzoni82ef29a2016-05-10 23:37:51594void AccessibilityManager::HandleAccessibilityGesture(ui::AXGesture gesture) {
595 extensions::EventRouter* event_router =
596 extensions::EventRouter::Get(profile());
597 CHECK(event_router);
598
599 std::unique_ptr<base::ListValue> event_args(new base::ListValue());
600 event_args->AppendString(ui::ToString(gesture));
601 std::unique_ptr<extensions::Event> event(new extensions::Event(
602 extensions::events::ACCESSIBILITY_PRIVATE_ON_ACCESSIBILITY_GESTURE,
603 extensions::api::accessibility_private::OnAccessibilityGesture::
604 kEventName,
605 std::move(event_args)));
606 event_router->DispatchEventWithLazyListener(
607 extension_misc::kChromeVoxExtensionId, std::move(event));
608}
609
dmazzoniff86e3472016-06-03 19:52:32610void AccessibilityManager::SetTouchAccessibilityAnchorPoint(
611 const gfx::Point& anchor_point) {
612 ash::RootWindowController* root_window_controller =
613 ash::RootWindowController::ForTargetRootWindow();
614 root_window_controller->SetTouchAccessibilityAnchorPoint(anchor_point);
615}
616
[email protected]1dfebfc2013-06-04 03:14:32617bool AccessibilityManager::IsHighContrastEnabled() {
618 return high_contrast_enabled_;
619}
620
[email protected]1c881562013-10-12 07:52:58621void AccessibilityManager::EnableAutoclick(bool enabled) {
622 if (!profile_)
623 return;
624
625 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19626 pref_service->SetBoolean(prefs::kAccessibilityAutoclickEnabled, enabled);
[email protected]1c881562013-10-12 07:52:58627 pref_service->CommitPendingWrite();
628}
629
630bool AccessibilityManager::IsAutoclickEnabled() {
631 return autoclick_enabled_;
632}
633
634void AccessibilityManager::UpdateAutoclickFromPref() {
ginkagebda078c2014-12-15 14:24:53635 if (!profile_)
636 return;
637
[email protected]1c881562013-10-12 07:52:58638 bool enabled =
[email protected]ced247a2014-06-13 19:14:19639 profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityAutoclickEnabled);
[email protected]1c881562013-10-12 07:52:58640
641 if (autoclick_enabled_ == enabled)
642 return;
643 autoclick_enabled_ = enabled;
644
riajiang4b626b972016-09-13 16:12:49645 if (chrome::IsRunningInMash()) {
rockot400ea35b2016-10-15 19:15:32646 service_manager::Connector* connector =
bend32292b2016-10-07 00:21:58647 content::ServiceManagerConnection::GetForProcess()->GetConnector();
riajiang4b626b972016-09-13 16:12:49648 mash::mojom::LaunchablePtr launchable;
ben72b077632016-11-16 00:23:53649 connector->ConnectToInterface("accessibility_autoclick", &launchable);
riajiang4b626b972016-09-13 16:12:49650 launchable->Launch(mash::mojom::kWindow, mash::mojom::LaunchMode::DEFAULT);
651 return;
652 }
653
[email protected]1c881562013-10-12 07:52:58654 ash::Shell::GetInstance()->autoclick_controller()->SetEnabled(enabled);
[email protected]1c881562013-10-12 07:52:58655}
656
[email protected]84d652d2013-10-23 13:57:57657void AccessibilityManager::SetAutoclickDelay(int delay_ms) {
658 if (!profile_)
659 return;
660
661 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19662 pref_service->SetInteger(prefs::kAccessibilityAutoclickDelayMs, delay_ms);
[email protected]84d652d2013-10-23 13:57:57663 pref_service->CommitPendingWrite();
664}
665
666int AccessibilityManager::GetAutoclickDelay() const {
riajiang4b626b972016-09-13 16:12:49667 return static_cast<int>(autoclick_delay_ms_.InMilliseconds());
[email protected]84d652d2013-10-23 13:57:57668}
669
670void AccessibilityManager::UpdateAutoclickDelayFromPref() {
ginkagebda078c2014-12-15 14:24:53671 if (!profile_)
672 return;
673
sammiequon820646f2016-06-24 18:47:13674 base::TimeDelta autoclick_delay_ms = base::TimeDelta::FromMilliseconds(
675 int64_t{profile_->GetPrefs()->GetInteger(
676 prefs::kAccessibilityAutoclickDelayMs)});
[email protected]84d652d2013-10-23 13:57:57677
678 if (autoclick_delay_ms == autoclick_delay_ms_)
679 return;
680 autoclick_delay_ms_ = autoclick_delay_ms;
681
riajiang4b626b972016-09-13 16:12:49682 if (chrome::IsRunningInMash()) {
rockot400ea35b2016-10-15 19:15:32683 service_manager::Connector* connector =
bend32292b2016-10-07 00:21:58684 content::ServiceManagerConnection::GetForProcess()->GetConnector();
riajiang4b626b972016-09-13 16:12:49685 ash::autoclick::mojom::AutoclickControllerPtr autoclick_controller;
ben72b077632016-11-16 00:23:53686 connector->ConnectToInterface("accessibility_autoclick",
riajiang4b626b972016-09-13 16:12:49687 &autoclick_controller);
688 autoclick_controller->SetAutoclickDelay(
689 autoclick_delay_ms_.InMilliseconds());
690 return;
691 }
692
[email protected]84d652d2013-10-23 13:57:57693 ash::Shell::GetInstance()->autoclick_controller()->SetAutoclickDelay(
694 autoclick_delay_ms_);
[email protected]84d652d2013-10-23 13:57:57695}
696
[email protected]e1b299b2014-01-29 23:53:41697void AccessibilityManager::EnableVirtualKeyboard(bool enabled) {
698 if (!profile_)
699 return;
700
701 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19702 pref_service->SetBoolean(prefs::kAccessibilityVirtualKeyboardEnabled,
703 enabled);
[email protected]e1b299b2014-01-29 23:53:41704 pref_service->CommitPendingWrite();
705}
706
707bool AccessibilityManager::IsVirtualKeyboardEnabled() {
708 return virtual_keyboard_enabled_;
709}
710
711void AccessibilityManager::UpdateVirtualKeyboardFromPref() {
712 if (!profile_)
713 return;
714
[email protected]ced247a2014-06-13 19:14:19715 const bool enabled = profile_->GetPrefs()->GetBoolean(
716 prefs::kAccessibilityVirtualKeyboardEnabled);
[email protected]e1b299b2014-01-29 23:53:41717
718 if (virtual_keyboard_enabled_ == enabled)
719 return;
720 virtual_keyboard_enabled_ = enabled;
721
[email protected]e1b299b2014-01-29 23:53:41722 keyboard::SetAccessibilityKeyboardEnabled(enabled);
msw15156bf2016-09-13 21:49:17723 if (!chrome::IsRunningInMash()) {
724 // Note that there are two versions of the on-screen keyboard. A full layout
725 // is provided for accessibility, which includes sticky modifier keys to
726 // enable typing of hotkeys. A compact version is used in touchview mode
727 // to provide a layout with larger keys to facilitate touch typing. In the
728 // event that the a11y keyboard is being disabled, an on-screen keyboard
729 // might still be enabled and a forced reset is required to pick up the
730 // layout change.
731 if (keyboard::IsKeyboardEnabled())
732 ash::Shell::GetInstance()->CreateKeyboard();
733 else
734 ash::Shell::GetInstance()->DeactivateKeyboard();
735 } else {
736 // TODO(mash): Support on-screen keyboard. See http://crbug.com/646565
737 NOTIMPLEMENTED();
738 }
rsadama1104b82014-11-03 20:50:52739
jamescooka7f8dab2016-06-21 01:44:03740 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_VIRTUAL_KEYBOARD,
741 enabled, ash::A11Y_NOTIFICATION_NONE);
rsadama1104b82014-11-03 20:50:52742 NotifyAccessibilityStatusChanged(details);
[email protected]e1b299b2014-01-29 23:53:41743}
744
warx533c8f62016-04-12 01:19:43745void AccessibilityManager::EnableMonoAudio(bool enabled) {
746 if (!profile_)
747 return;
748
749 PrefService* pref_service = profile_->GetPrefs();
750 pref_service->SetBoolean(prefs::kAccessibilityMonoAudioEnabled,
751 enabled);
752 pref_service->CommitPendingWrite();
753}
754
755bool AccessibilityManager::IsMonoAudioEnabled() {
756 return mono_audio_enabled_;
757}
758
759void AccessibilityManager::UpdateMonoAudioFromPref() {
760 if (!profile_)
761 return;
762
763 const bool enabled = profile_->GetPrefs()->GetBoolean(
764 prefs::kAccessibilityMonoAudioEnabled);
765
766 if (mono_audio_enabled_ == enabled)
767 return;
768 mono_audio_enabled_ = enabled;
769
jamescooka7f8dab2016-06-21 01:44:03770 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_MONO_AUDIO,
771 enabled, ash::A11Y_NOTIFICATION_NONE);
warx533c8f62016-04-12 01:19:43772 NotifyAccessibilityStatusChanged(details);
773
774 ash::Shell::GetInstance()->audio_a11y_controller()->SetOutputMono(enabled);
775}
776
dmazzoni756089a22016-03-15 23:55:16777void AccessibilityManager::SetCaretHighlightEnabled(bool enabled) {
778 if (!profile_)
779 return;
780
781 PrefService* pref_service = profile_->GetPrefs();
782 pref_service->SetBoolean(prefs::kAccessibilityCaretHighlightEnabled, enabled);
783 pref_service->CommitPendingWrite();
784}
785
786bool AccessibilityManager::IsCaretHighlightEnabled() const {
787 return caret_highlight_enabled_;
788}
789
790void AccessibilityManager::UpdateCaretHighlightFromPref() {
791 if (!profile_)
792 return;
793
794 const bool enabled = profile_->GetPrefs()->GetBoolean(
795 prefs::kAccessibilityCaretHighlightEnabled);
796
797 if (caret_highlight_enabled_ == enabled)
798 return;
799 caret_highlight_enabled_ = enabled;
800
dmazzonib93107c2016-03-22 21:51:18801 UpdateAccessibilityHighlightingFromPrefs();
dmazzoni756089a22016-03-15 23:55:16802}
803
804void AccessibilityManager::SetCursorHighlightEnabled(bool enabled) {
805 if (!profile_)
806 return;
807
808 PrefService* pref_service = profile_->GetPrefs();
809 pref_service->SetBoolean(prefs::kAccessibilityCursorHighlightEnabled,
810 enabled);
811 pref_service->CommitPendingWrite();
812}
813
814bool AccessibilityManager::IsCursorHighlightEnabled() const {
815 return cursor_highlight_enabled_;
816}
817
818void AccessibilityManager::UpdateCursorHighlightFromPref() {
819 if (!profile_)
820 return;
821
822 const bool enabled = profile_->GetPrefs()->GetBoolean(
823 prefs::kAccessibilityCursorHighlightEnabled);
824
825 if (cursor_highlight_enabled_ == enabled)
826 return;
827 cursor_highlight_enabled_ = enabled;
828
dmazzonib93107c2016-03-22 21:51:18829 UpdateAccessibilityHighlightingFromPrefs();
dmazzoni756089a22016-03-15 23:55:16830}
831
832void AccessibilityManager::SetFocusHighlightEnabled(bool enabled) {
833 if (!profile_)
834 return;
835
836 PrefService* pref_service = profile_->GetPrefs();
837 pref_service->SetBoolean(prefs::kAccessibilityFocusHighlightEnabled, enabled);
838 pref_service->CommitPendingWrite();
839}
840
841bool AccessibilityManager::IsFocusHighlightEnabled() const {
842 return focus_highlight_enabled_;
843}
844
845void AccessibilityManager::UpdateFocusHighlightFromPref() {
846 if (!profile_)
847 return;
848
dmazzoni42e4b002016-06-08 20:58:42849 bool enabled = profile_->GetPrefs()->GetBoolean(
dmazzoni756089a22016-03-15 23:55:16850 prefs::kAccessibilityFocusHighlightEnabled);
851
dmazzoni42e4b002016-06-08 20:58:42852 // Focus highlighting can't be on when spoken feedback is on, because
853 // ChromeVox does its own focus highlighting.
854 if (profile_->GetPrefs()->GetBoolean(
855 prefs::kAccessibilitySpokenFeedbackEnabled))
856 enabled = false;
857
dmazzoni756089a22016-03-15 23:55:16858 if (focus_highlight_enabled_ == enabled)
859 return;
860 focus_highlight_enabled_ = enabled;
861
dmazzonib93107c2016-03-22 21:51:18862 UpdateAccessibilityHighlightingFromPrefs();
dmazzoni756089a22016-03-15 23:55:16863}
864
865void AccessibilityManager::SetSelectToSpeakEnabled(bool enabled) {
866 if (!profile_)
867 return;
868
869 PrefService* pref_service = profile_->GetPrefs();
870 pref_service->SetBoolean(prefs::kAccessibilitySelectToSpeakEnabled, enabled);
871 pref_service->CommitPendingWrite();
872}
873
874bool AccessibilityManager::IsSelectToSpeakEnabled() const {
875 return select_to_speak_enabled_;
876}
877
878void AccessibilityManager::UpdateSelectToSpeakFromPref() {
879 if (!profile_)
880 return;
881
882 const bool enabled = profile_->GetPrefs()->GetBoolean(
883 prefs::kAccessibilitySelectToSpeakEnabled);
884
885 if (select_to_speak_enabled_ == enabled)
886 return;
887 select_to_speak_enabled_ = enabled;
888
dmazzoni5288b2612016-09-16 23:05:39889 if (enabled) {
890 select_to_speak_loader_->Load(profile_, "" /* init_script_str */,
891 base::Closure() /* done_cb */);
dmazzoni735c79df2016-11-28 22:39:42892 select_to_speak_event_handler_.reset(
893 new chromeos::SelectToSpeakEventHandler());
dmazzoni5288b2612016-09-16 23:05:39894 } else {
895 select_to_speak_loader_->Unload();
dmazzoni735c79df2016-11-28 22:39:42896 select_to_speak_event_handler_.reset(nullptr);
dmazzoni5288b2612016-09-16 23:05:39897 }
dmazzoni756089a22016-03-15 23:55:16898}
899
900void AccessibilityManager::SetSwitchAccessEnabled(bool enabled) {
901 if (!profile_)
902 return;
903
904 PrefService* pref_service = profile_->GetPrefs();
905 pref_service->SetBoolean(prefs::kAccessibilitySwitchAccessEnabled, enabled);
906 pref_service->CommitPendingWrite();
907}
908
909bool AccessibilityManager::IsSwitchAccessEnabled() const {
910 return switch_access_enabled_;
911}
912
913void AccessibilityManager::UpdateSwitchAccessFromPref() {
914 if (!profile_)
915 return;
916
917 const bool enabled = profile_->GetPrefs()->GetBoolean(
918 prefs::kAccessibilitySwitchAccessEnabled);
919
920 if (switch_access_enabled_ == enabled)
921 return;
922 switch_access_enabled_ = enabled;
923
924 // TODO(dmazzoni): implement feature here.
925}
926
dmazzonib93107c2016-03-22 21:51:18927void AccessibilityManager::UpdateAccessibilityHighlightingFromPrefs() {
928 if (!focus_highlight_enabled_ && !caret_highlight_enabled_ &&
929 !cursor_highlight_enabled_) {
930 if (accessibility_highlight_manager_)
931 accessibility_highlight_manager_.reset();
932 return;
933 }
934
dmazzoni7fb1f572016-06-18 00:06:17935 if (!accessibility_highlight_manager_) {
dmazzonib93107c2016-03-22 21:51:18936 accessibility_highlight_manager_.reset(new AccessibilityHighlightManager());
dmazzoni7fb1f572016-06-18 00:06:17937 accessibility_highlight_manager_->RegisterObservers();
938 }
dmazzonib93107c2016-03-22 21:51:18939
940 accessibility_highlight_manager_->HighlightFocus(focus_highlight_enabled_);
941 accessibility_highlight_manager_->HighlightCaret(caret_highlight_enabled_);
942 accessibility_highlight_manager_->HighlightCursor(cursor_highlight_enabled_);
943}
944
[email protected]a81b2c32014-03-28 06:35:01945bool AccessibilityManager::IsBrailleDisplayConnected() const {
946 return braille_display_connected_;
947}
948
[email protected]8c79e3f2013-10-30 01:05:14949void AccessibilityManager::CheckBrailleState() {
[email protected]a81b2c32014-03-28 06:35:01950 BrailleController* braille_controller = GetBrailleController();
951 if (!scoped_braille_observer_.IsObserving(braille_controller))
952 scoped_braille_observer_.Add(braille_controller);
[email protected]8c79e3f2013-10-30 01:05:14953 BrowserThread::PostTaskAndReplyWithResult(
[email protected]a81b2c32014-03-28 06:35:01954 BrowserThread::IO,
955 FROM_HERE,
956 base::Bind(&BrailleController::GetDisplayState,
957 base::Unretained(braille_controller)),
[email protected]8c79e3f2013-10-30 01:05:14958 base::Bind(&AccessibilityManager::ReceiveBrailleDisplayState,
959 weak_ptr_factory_.GetWeakPtr()));
960}
961
962void AccessibilityManager::ReceiveBrailleDisplayState(
dcheng24002d02016-04-08 02:42:40963 std::unique_ptr<extensions::api::braille_display_private::DisplayState>
964 state) {
[email protected]2e5e0b12014-05-07 13:30:20965 OnBrailleDisplayStateChanged(*state);
966}
967
968void AccessibilityManager::UpdateBrailleImeState() {
969 if (!profile_)
970 return;
971 PrefService* pref_service = profile_->GetPrefs();
brettwc6f82b12015-07-21 21:37:38972 std::vector<std::string> preload_engines =
973 base::SplitString(pref_service->GetString(prefs::kLanguagePreloadEngines),
974 ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
[email protected]2e5e0b12014-05-07 13:30:20975 std::vector<std::string>::iterator it =
976 std::find(preload_engines.begin(),
977 preload_engines.end(),
978 extension_misc::kBrailleImeEngineId);
979 bool is_enabled = (it != preload_engines.end());
980 bool should_be_enabled =
981 (spoken_feedback_enabled_ && braille_display_connected_);
982 if (is_enabled == should_be_enabled)
983 return;
984 if (should_be_enabled)
985 preload_engines.push_back(extension_misc::kBrailleImeEngineId);
986 else
987 preload_engines.erase(it);
988 pref_service->SetString(prefs::kLanguagePreloadEngines,
brettwd94a22142015-07-15 05:19:26989 base::JoinString(preload_engines, ","));
[email protected]2e5e0b12014-05-07 13:30:20990 braille_ime_current_ = false;
[email protected]8c79e3f2013-10-30 01:05:14991}
992
[email protected]1488a035f2014-03-28 21:12:07993// Overridden from InputMethodManager::Observer.
994void AccessibilityManager::InputMethodChanged(
995 input_method::InputMethodManager* manager,
alematef06730292015-05-12 21:36:07996 Profile* /* profile */,
[email protected]1488a035f2014-03-28 21:12:07997 bool show_message) {
[email protected]1488a035f2014-03-28 21:12:07998 // Sticky keys is implemented only in ash.
dpolukhin04e5b8092014-09-11 02:55:05999 // TODO(dpolukhin): support Athena, crbug.com/408733.
riajiang4b626b972016-09-13 16:12:491000 if (!chrome::IsRunningInMash()) {
1001 ash::Shell::GetInstance()->sticky_keys_controller()->SetModifiersEnabled(
1002 manager->IsISOLevel5ShiftUsedByCurrentInputMethod(),
1003 manager->IsAltGrUsedByCurrentInputMethod());
1004 }
[email protected]2e5e0b12014-05-07 13:30:201005 const chromeos::input_method::InputMethodDescriptor descriptor =
[email protected]f0881cf2014-08-15 23:31:421006 manager->GetActiveIMEState()->GetCurrentInputMethod();
[email protected]2e5e0b12014-05-07 13:30:201007 braille_ime_current_ =
1008 (descriptor.id() == extension_misc::kBrailleImeEngineId);
[email protected]1488a035f2014-03-28 21:12:071009}
[email protected]8c79e3f2013-10-30 01:05:141010
[email protected]1dfebfc2013-06-04 03:14:321011void AccessibilityManager::SetProfile(Profile* profile) {
1012 pref_change_registrar_.reset();
[email protected]d1d5f4f2013-06-14 07:17:091013 local_state_pref_change_registrar_.reset();
[email protected]1dfebfc2013-06-04 03:14:321014
1015 if (profile) {
[email protected]0aae2fe2013-07-05 07:04:421016 // TODO(yoshiki): Move following code to PrefHandler.
[email protected]1dfebfc2013-06-04 03:14:321017 pref_change_registrar_.reset(new PrefChangeRegistrar);
1018 pref_change_registrar_->Init(profile->GetPrefs());
1019 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191020 prefs::kAccessibilityLargeCursorEnabled,
[email protected]d80f19302013-06-07 13:12:141021 base::Bind(&AccessibilityManager::UpdateLargeCursorFromPref,
[email protected]8126b812013-06-06 03:49:171022 base::Unretained(this)));
1023 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191024 prefs::kAccessibilityStickyKeysEnabled,
[email protected]93a534e2013-06-20 16:41:441025 base::Bind(&AccessibilityManager::UpdateStickyKeysFromPref,
1026 base::Unretained(this)));
1027 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191028 prefs::kAccessibilitySpokenFeedbackEnabled,
[email protected]d80f19302013-06-07 13:12:141029 base::Bind(&AccessibilityManager::UpdateSpokenFeedbackFromPref,
[email protected]1dfebfc2013-06-04 03:14:321030 base::Unretained(this)));
1031 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191032 prefs::kAccessibilityHighContrastEnabled,
[email protected]d80f19302013-06-07 13:12:141033 base::Bind(&AccessibilityManager::UpdateHighContrastFromPref,
[email protected]1dfebfc2013-06-04 03:14:321034 base::Unretained(this)));
[email protected]1c881562013-10-12 07:52:581035 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191036 prefs::kAccessibilityAutoclickEnabled,
[email protected]1c881562013-10-12 07:52:581037 base::Bind(&AccessibilityManager::UpdateAutoclickFromPref,
1038 base::Unretained(this)));
[email protected]84d652d2013-10-23 13:57:571039 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191040 prefs::kAccessibilityAutoclickDelayMs,
[email protected]84d652d2013-10-23 13:57:571041 base::Bind(&AccessibilityManager::UpdateAutoclickDelayFromPref,
1042 base::Unretained(this)));
[email protected]e1b299b2014-01-29 23:53:411043 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191044 prefs::kAccessibilityVirtualKeyboardEnabled,
[email protected]e1b299b2014-01-29 23:53:411045 base::Bind(&AccessibilityManager::UpdateVirtualKeyboardFromPref,
1046 base::Unretained(this)));
dmazzoni756089a22016-03-15 23:55:161047 pref_change_registrar_->Add(
warx533c8f62016-04-12 01:19:431048 prefs::kAccessibilityMonoAudioEnabled,
1049 base::Bind(&AccessibilityManager::UpdateMonoAudioFromPref,
1050 base::Unretained(this)));
1051 pref_change_registrar_->Add(
dmazzoni756089a22016-03-15 23:55:161052 prefs::kAccessibilityCaretHighlightEnabled,
1053 base::Bind(&AccessibilityManager::UpdateCaretHighlightFromPref,
1054 base::Unretained(this)));
1055 pref_change_registrar_->Add(
1056 prefs::kAccessibilityCursorHighlightEnabled,
1057 base::Bind(&AccessibilityManager::UpdateCursorHighlightFromPref,
1058 base::Unretained(this)));
1059 pref_change_registrar_->Add(
1060 prefs::kAccessibilityFocusHighlightEnabled,
1061 base::Bind(&AccessibilityManager::UpdateFocusHighlightFromPref,
1062 base::Unretained(this)));
1063 pref_change_registrar_->Add(
1064 prefs::kAccessibilitySelectToSpeakEnabled,
1065 base::Bind(&AccessibilityManager::UpdateSelectToSpeakFromPref,
1066 base::Unretained(this)));
1067 pref_change_registrar_->Add(
1068 prefs::kAccessibilitySwitchAccessEnabled,
1069 base::Bind(&AccessibilityManager::UpdateSwitchAccessFromPref,
1070 base::Unretained(this)));
[email protected]1dfebfc2013-06-04 03:14:321071
[email protected]d1d5f4f2013-06-14 07:17:091072 local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
1073 local_state_pref_change_registrar_->Init(g_browser_process->local_state());
1074 local_state_pref_change_registrar_->Add(
1075 prefs::kApplicationLocale,
[email protected]628b8902014-03-12 05:26:411076 base::Bind(&AccessibilityManager::OnLocaleChanged,
[email protected]d1d5f4f2013-06-14 07:17:091077 base::Unretained(this)));
1078
[email protected]1dfebfc2013-06-04 03:14:321079 content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback(
1080 base::Bind(
1081 &AccessibilityManager::UpdateChromeOSAccessibilityHistograms,
1082 base::Unretained(this)));
dmazzoni337c5af2016-09-13 23:08:571083
dmazzoni337c5af2016-09-13 23:08:571084 extensions::ExtensionRegistry* registry =
1085 extensions::ExtensionRegistry::Get(profile);
1086 if (!extension_registry_observer_.IsObserving(registry))
1087 extension_registry_observer_.Add(registry);
[email protected]1dfebfc2013-06-04 03:14:321088 }
1089
[email protected]0aae2fe2013-07-05 07:04:421090 large_cursor_pref_handler_.HandleProfileChanged(profile_, profile);
1091 spoken_feedback_pref_handler_.HandleProfileChanged(profile_, profile);
1092 high_contrast_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]1c881562013-10-12 07:52:581093 autoclick_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]84d652d2013-10-23 13:57:571094 autoclick_delay_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]42b471f2014-01-31 20:31:291095 virtual_keyboard_pref_handler_.HandleProfileChanged(profile_, profile);
warx533c8f62016-04-12 01:19:431096 mono_audio_pref_handler_.HandleProfileChanged(profile_, profile);
dmazzoni756089a22016-03-15 23:55:161097 caret_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1098 cursor_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1099 focus_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1100 select_to_speak_pref_handler_.HandleProfileChanged(profile_, profile);
1101 switch_access_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]0aae2fe2013-07-05 07:04:421102
[email protected]a81b2c32014-03-28 06:35:011103 bool had_profile = (profile_ != NULL);
1104 profile_ = profile;
1105
1106 if (!had_profile && profile)
[email protected]8c79e3f2013-10-30 01:05:141107 CheckBrailleState();
[email protected]2e5e0b12014-05-07 13:30:201108 else
1109 UpdateBrailleImeState();
[email protected]d80f19302013-06-07 13:12:141110 UpdateLargeCursorFromPref();
[email protected]93a534e2013-06-20 16:41:441111 UpdateStickyKeysFromPref();
[email protected]d80f19302013-06-07 13:12:141112 UpdateSpokenFeedbackFromPref();
1113 UpdateHighContrastFromPref();
[email protected]1c881562013-10-12 07:52:581114 UpdateAutoclickFromPref();
[email protected]84d652d2013-10-23 13:57:571115 UpdateAutoclickDelayFromPref();
[email protected]e1b299b2014-01-29 23:53:411116 UpdateVirtualKeyboardFromPref();
warx533c8f62016-04-12 01:19:431117 UpdateMonoAudioFromPref();
dmazzoni756089a22016-03-15 23:55:161118 UpdateCaretHighlightFromPref();
1119 UpdateCursorHighlightFromPref();
1120 UpdateFocusHighlightFromPref();
1121 UpdateSelectToSpeakFromPref();
1122 UpdateSwitchAccessFromPref();
dmazzoni39d6d4b2016-03-29 22:18:001123
1124 // Update the panel height in the shelf layout manager when the profile
1125 // changes, since the shelf layout manager doesn't exist in the login profile.
1126 if (chromevox_panel_)
1127 chromevox_panel_->UpdatePanelHeight();
[email protected]1dfebfc2013-06-04 03:14:321128}
1129
alematecdf46dd2015-11-12 03:15:161130void AccessibilityManager::ActiveUserChanged(const AccountId& account_id) {
[email protected]c20122572013-12-16 20:35:581131 SetProfile(ProfileManager::GetActiveUserProfile());
1132}
1133
achuithecf113f2015-09-10 10:09:191134void AccessibilityManager::OnAppTerminating() {
1135 session_state_observer_.reset();
1136}
1137
sky80556bc42016-06-07 22:46:131138void AccessibilityManager::OnFullscreenStateChanged(
1139 bool is_fullscreen,
1140 ash::WmWindow* root_window) {
dmazzonid47388d2016-03-31 16:03:511141 if (chromevox_panel_)
1142 chromevox_panel_->UpdateWidgetBounds();
1143}
1144
[email protected]1dfebfc2013-06-04 03:14:321145void AccessibilityManager::SetProfileForTest(Profile* profile) {
1146 SetProfile(profile);
1147}
1148
[email protected]8c79e3f2013-10-30 01:05:141149void AccessibilityManager::SetBrailleControllerForTest(
1150 BrailleController* controller) {
1151 g_braille_controller_for_test = controller;
1152}
1153
[email protected]ce89d9392013-12-11 21:05:201154void AccessibilityManager::EnableSystemSounds(bool system_sounds_enabled) {
1155 system_sounds_enabled_ = system_sounds_enabled;
1156}
1157
1158base::TimeDelta AccessibilityManager::PlayShutdownSound() {
[email protected]4f011f12014-01-15 08:22:451159 if (!system_sounds_enabled_)
[email protected]ce89d9392013-12-11 21:05:201160 return base::TimeDelta();
1161 system_sounds_enabled_ = false;
sadrulcdc2bb42016-07-13 19:44:511162 if (!PlayEarcon(SOUND_SHUTDOWN, PlaySoundOption::SPOKEN_FEEDBACK_ENABLED))
[email protected]4f011f12014-01-15 08:22:451163 return base::TimeDelta();
1164 return media::SoundsManager::Get()->GetDuration(SOUND_SHUTDOWN);
[email protected]ce89d9392013-12-11 21:05:201165}
1166
[email protected]f8aa76842014-02-05 19:11:061167void AccessibilityManager::InjectChromeVox(RenderViewHost* render_view_host) {
dmazzoni337c5af2016-09-13 23:08:571168 chromevox_loader_->LoadExtension(profile_, render_view_host, base::Closure());
[email protected]f8aa76842014-02-05 19:11:061169}
1170
dcheng24002d02016-04-08 02:42:401171std::unique_ptr<AccessibilityStatusSubscription>
1172AccessibilityManager::RegisterCallback(const AccessibilityStatusCallback& cb) {
[email protected]d8edc9c2014-02-25 00:06:031173 return callback_list_.Add(cb);
1174}
1175
1176void AccessibilityManager::NotifyAccessibilityStatusChanged(
1177 AccessibilityStatusEventDetails& details) {
1178 callback_list_.Notify(details);
1179}
1180
[email protected]1dfebfc2013-06-04 03:14:321181void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
1182 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
1183 IsSpokenFeedbackEnabled());
1184 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast",
1185 IsHighContrastEnabled());
1186 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard",
[email protected]e1b299b2014-01-29 23:53:411187 IsVirtualKeyboardEnabled());
[email protected]7fb7ea42014-02-12 21:19:311188 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
[email protected]1dfebfc2013-06-04 03:14:321189 if (MagnificationManager::Get()) {
avi8a07d53892015-12-24 22:13:531190 uint32_t type = MagnificationManager::Get()->IsMagnifierEnabled()
1191 ? MagnificationManager::Get()->GetMagnifierType()
1192 : 0;
[email protected]1dfebfc2013-06-04 03:14:321193 // '0' means magnifier is disabled.
jamescooka7f8dab2016-06-21 01:44:031194 UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosScreenMagnifier", type,
1195 ash::kMaxMagnifierType + 1);
[email protected]1dfebfc2013-06-04 03:14:321196 }
[email protected]ca3a0a82013-06-18 06:52:121197 if (profile_) {
1198 const PrefService* const prefs = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:191199 UMA_HISTOGRAM_BOOLEAN(
1200 "Accessibility.CrosLargeCursor",
1201 prefs->GetBoolean(prefs::kAccessibilityLargeCursorEnabled));
[email protected]ca3a0a82013-06-18 06:52:121202 UMA_HISTOGRAM_BOOLEAN(
1203 "Accessibility.CrosAlwaysShowA11yMenu",
1204 prefs->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu));
[email protected]0b5a0d2b2013-10-30 03:43:401205
[email protected]ced247a2014-06-13 19:14:191206 bool autoclick_enabled =
1207 prefs->GetBoolean(prefs::kAccessibilityAutoclickEnabled);
[email protected]0b5a0d2b2013-10-30 03:43:401208 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
1209 if (autoclick_enabled) {
1210 // We only want to log the autoclick delay if the user has actually
1211 // enabled autoclick.
1212 UMA_HISTOGRAM_CUSTOM_TIMES(
1213 "Accessibility.CrosAutoclickDelay",
1214 base::TimeDelta::FromMilliseconds(
[email protected]ced247a2014-06-13 19:14:191215 prefs->GetInteger(prefs::kAccessibilityAutoclickDelayMs)),
[email protected]0b5a0d2b2013-10-30 03:43:401216 base::TimeDelta::FromMilliseconds(1),
1217 base::TimeDelta::FromMilliseconds(3000),
1218 50);
1219 }
[email protected]ca3a0a82013-06-18 06:52:121220 }
dmazzoni756089a22016-03-15 23:55:161221 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCaretHighlight",
1222 IsCaretHighlightEnabled());
1223 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCursorHighlight",
1224 IsCursorHighlightEnabled());
1225 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosFocusHighlight",
1226 IsFocusHighlightEnabled());
1227 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSelectToSpeak",
1228 IsSelectToSpeakEnabled());
1229 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccess",
1230 IsSwitchAccessEnabled());
[email protected]1dfebfc2013-06-04 03:14:321231}
1232
1233void AccessibilityManager::Observe(
1234 int type,
1235 const content::NotificationSource& source,
1236 const content::NotificationDetails& details) {
1237 switch (type) {
[email protected]093d9ba2013-07-23 19:26:211238 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
[email protected]9cf54f362013-07-01 07:28:121239 // Update |profile_| when entering the login screen.
[email protected]c20122572013-12-16 20:35:581240 Profile* profile = ProfileManager::GetActiveUserProfile();
[email protected]d888cdc2013-06-24 17:06:201241 if (ProfileHelper::IsSigninProfile(profile))
1242 SetProfile(profile);
[email protected]1dfebfc2013-06-04 03:14:321243 break;
[email protected]d888cdc2013-06-24 17:06:201244 }
[email protected]e6f20642013-06-11 17:05:461245 case chrome::NOTIFICATION_SESSION_STARTED:
1246 // Update |profile_| when entering a session.
[email protected]c20122572013-12-16 20:35:581247 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]0e9504d2013-11-05 02:33:291248
1249 // Ensure ChromeVox makes announcements at the start of new sessions.
1250 should_speak_chrome_vox_announcements_on_user_screen_ = true;
[email protected]c20122572013-12-16 20:35:581251
1252 // Add a session state observer to be able to monitor session changes.
1253 if (!session_state_observer_.get() && ash::Shell::HasInstance())
1254 session_state_observer_.reset(
1255 new ash::ScopedSessionStateObserver(this));
[email protected]1dfebfc2013-06-04 03:14:321256 break;
[email protected]1dfebfc2013-06-04 03:14:321257 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
[email protected]e6f20642013-06-11 17:05:461258 // Update |profile_| when exiting a session or shutting down.
1259 Profile* profile = content::Source<Profile>(source).ptr();
1260 if (profile_ == profile)
1261 SetProfile(NULL);
[email protected]1dfebfc2013-06-04 03:14:321262 break;
1263 }
[email protected]b0a2ce32013-07-23 15:24:531264 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
1265 bool is_screen_locked = *content::Details<bool>(details).ptr();
[email protected]9d6c91362013-12-07 21:56:271266 if (spoken_feedback_enabled_) {
[email protected]44beb032014-06-11 06:24:371267 if (is_screen_locked)
dmazzoni337c5af2016-09-13 23:08:571268 chromevox_loader_->LoadToLockScreen(base::Closure());
[email protected]44beb032014-06-11 06:24:371269 // If spoken feedback was enabled, make sure it is also enabled on
1270 // the user screen.
1271 // The status tray gets verbalized by user screen ChromeVox, so we need
1272 // to load it on the user screen even if the screen is locked.
dmazzoni337c5af2016-09-13 23:08:571273 chromevox_loader_->LoadToUserScreen(base::Closure());
[email protected]b0a2ce32013-07-23 15:24:531274 }
[email protected]9d6c91362013-12-07 21:56:271275 break;
1276 }
[email protected]1dfebfc2013-06-04 03:14:321277 }
1278}
1279
[email protected]2e5e0b12014-05-07 13:30:201280void AccessibilityManager::OnBrailleDisplayStateChanged(
[email protected]8c79e3f2013-10-30 01:05:141281 const DisplayState& display_state) {
[email protected]a81b2c32014-03-28 06:35:011282 braille_display_connected_ = display_state.available;
[email protected]2e5e0b12014-05-07 13:30:201283 if (braille_display_connected_) {
jamescooka7f8dab2016-06-21 01:44:031284 EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_SHOW);
[email protected]2e5e0b12014-05-07 13:30:201285 }
1286 UpdateBrailleImeState();
[email protected]a81b2c32014-03-28 06:35:011287
1288 AccessibilityStatusEventDetails details(
1289 ACCESSIBILITY_BRAILLE_DISPLAY_CONNECTION_STATE_CHANGED,
jamescooka7f8dab2016-06-21 01:44:031290 braille_display_connected_, ash::A11Y_NOTIFICATION_SHOW);
[email protected]a81b2c32014-03-28 06:35:011291 NotifyAccessibilityStatusChanged(details);
[email protected]8c79e3f2013-10-30 01:05:141292}
[email protected]0e9504d2013-11-05 02:33:291293
[email protected]2e5e0b12014-05-07 13:30:201294void AccessibilityManager::OnBrailleKeyEvent(const KeyEvent& event) {
1295 // Ensure the braille IME is active on braille keyboard (dots) input.
1296 if ((event.command ==
1297 extensions::api::braille_display_private::KEY_COMMAND_DOTS) &&
1298 !braille_ime_current_) {
[email protected]f0881cf2014-08-15 23:31:421299 input_method::InputMethodManager::Get()
1300 ->GetActiveIMEState()
1301 ->ChangeInputMethod(extension_misc::kBrailleImeEngineId,
1302 false /* show_message */);
[email protected]2e5e0b12014-05-07 13:30:201303 }
1304}
1305
dtsengfb6d7cd2016-01-20 23:00:131306void AccessibilityManager::OnExtensionUnloaded(
1307 content::BrowserContext* browser_context,
1308 const extensions::Extension* extension,
1309 extensions::UnloadedExtensionInfo::Reason reason) {
1310 if (extension->id() == keyboard_listener_extension_id_) {
1311 keyboard_listener_extension_id_ = std::string();
1312 keyboard_listener_capture_ = false;
dtsengfb6d7cd2016-01-20 23:00:131313 }
1314}
1315
1316void AccessibilityManager::OnShutdown(extensions::ExtensionRegistry* registry) {
1317 extension_registry_observer_.Remove(registry);
1318}
1319
dmazzoni337c5af2016-09-13 23:08:571320void AccessibilityManager::PostLoadChromeVox() {
[email protected]ee8bbd972014-02-03 06:52:471321 // Do any setup work needed immediately after ChromeVox actually loads.
sadrulcdc2bb42016-07-13 19:44:511322 PlayEarcon(SOUND_SPOKEN_FEEDBACK_ENABLED, PlaySoundOption::ALWAYS);
[email protected]0e9504d2013-11-05 02:33:291323
dmazzoni337c5af2016-09-13 23:08:571324 if (chromevox_loader_->loaded_on_lock_screen() ||
dtseng703a2042015-01-22 17:46:511325 should_speak_chrome_vox_announcements_on_user_screen_) {
juncaicf523332015-06-04 00:14:041326 extensions::EventRouter* event_router =
dmazzoni337c5af2016-09-13 23:08:571327 extensions::EventRouter::Get(profile_);
juncaicf523332015-06-04 00:14:041328 CHECK(event_router);
dtseng703a2042015-01-22 17:46:511329
dcheng24002d02016-04-08 02:42:401330 std::unique_ptr<base::ListValue> event_args(new base::ListValue());
1331 std::unique_ptr<extensions::Event> event(new extensions::Event(
Benjamin Kalmanfbf756f2015-06-25 22:56:201332 extensions::events::ACCESSIBILITY_PRIVATE_ON_INTRODUCE_CHROME_VOX,
1333 extensions::api::accessibility_private::OnIntroduceChromeVox::
1334 kEventName,
dcheng7c802f02015-12-31 16:09:551335 std::move(event_args)));
juncaicf523332015-06-04 00:14:041336 event_router->DispatchEventWithLazyListener(
dcheng7c802f02015-12-31 16:09:551337 extension_misc::kChromeVoxExtensionId, std::move(event));
dtseng703a2042015-01-22 17:46:511338 }
[email protected]0e9504d2013-11-05 02:33:291339
[email protected]c9eef112014-02-20 19:32:481340 should_speak_chrome_vox_announcements_on_user_screen_ =
dmazzoni337c5af2016-09-13 23:08:571341 chromevox_loader_->loaded_on_lock_screen();
dmazzoni94a4f882015-11-13 05:46:521342
1343 if (!chromevox_panel_) {
1344 chromevox_panel_ = new ChromeVoxPanel(profile_);
1345 chromevox_panel_widget_observer_.reset(
1346 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1347 }
dtsengd50debe32016-12-29 06:23:371348
1349 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1350 switches::kEnableDefaultMediaSession)) {
1351 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1352 switches::kEnableDefaultMediaSession);
1353 }
[email protected]0e9504d2013-11-05 02:33:291354}
1355
dmazzoni337c5af2016-09-13 23:08:571356void AccessibilityManager::PostUnloadChromeVox() {
[email protected]9d6c91362013-12-07 21:56:271357 // Do any teardown work needed immediately after ChromeVox actually unloads.
sadrulcdc2bb42016-07-13 19:44:511358 PlayEarcon(SOUND_SPOKEN_FEEDBACK_DISABLED, PlaySoundOption::ALWAYS);
dmazzonifb33d592014-10-30 19:26:541359 // Clear the accessibility focus ring.
1360 AccessibilityFocusRingController::GetInstance()->SetFocusRing(
dmazzoni42e4b002016-06-08 20:58:421361 std::vector<gfx::Rect>(),
1362 AccessibilityFocusRingController::PERSIST_FOCUS_RING);
dmazzoni337c5af2016-09-13 23:08:571363
1364 if (chromevox_panel_) {
1365 chromevox_panel_->Close();
1366 chromevox_panel_ = nullptr;
1367 }
[email protected]9d6c91362013-12-07 21:56:271368}
1369
dmazzoni63199b12016-10-19 15:44:361370void AccessibilityManager::PostSwitchChromeVoxProfile() {
1371 if (chromevox_panel_) {
1372 chromevox_panel_->Close();
1373 chromevox_panel_ = nullptr;
1374 }
1375 chromevox_panel_ = new ChromeVoxPanel(profile_);
1376 chromevox_panel_widget_observer_.reset(
1377 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1378}
1379
dmazzoni94a4f882015-11-13 05:46:521380void AccessibilityManager::OnChromeVoxPanelClosing() {
1381 aura::Window* root_window = chromevox_panel_->GetRootWindow();
1382 chromevox_panel_widget_observer_.reset(nullptr);
1383 chromevox_panel_ = nullptr;
dmazzoni39d6d4b2016-03-29 22:18:001384
jamescook1cad77e92016-08-31 00:02:261385 ash::WmShelf* shelf =
1386 ash::WmShelf::ForWindow(ash::WmWindowAura::Get(root_window));
1387 if (!shelf->IsShelfInitialized())
dmazzoni39d6d4b2016-03-29 22:18:001388 return;
1389
1390 ash::ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager();
1391 if (shelf_layout_manager)
1392 shelf_layout_manager->SetChromeVoxPanelHeight(0);
dmazzoni94a4f882015-11-13 05:46:521393}
1394
1395void AccessibilityManager::OnChromeVoxPanelDestroying() {
1396 chromevox_panel_widget_observer_.reset(nullptr);
1397 chromevox_panel_ = nullptr;
1398}
1399
dtsengfb6d7cd2016-01-20 23:00:131400void AccessibilityManager::SetKeyboardListenerExtensionId(
1401 const std::string& id,
1402 content::BrowserContext* context) {
1403 keyboard_listener_extension_id_ = id;
1404
1405 extensions::ExtensionRegistry* registry =
1406 extensions::ExtensionRegistry::Get(context);
1407 if (!extension_registry_observer_.IsObserving(registry) && !id.empty())
1408 extension_registry_observer_.Add(registry);
1409}
1410
[email protected]1dfebfc2013-06-04 03:14:321411} // namespace chromeos