blob: a3b6b00685555f18ffc11c55edd193ae1a4ea3d6 [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>
David Tseng8a5de492018-01-17 20:41:3712#include <vector>
avi8a07d53892015-12-24 22:13:5313
James Cook08e91dc2018-03-08 18:53:1914#include "ash/accessibility/accessibility_controller.h"
James Cookc63b9fd2017-08-18 18:48:3215#include "ash/public/cpp/ash_pref_names.h"
Qiang Xu56a75812018-03-15 00:28:3416#include "ash/public/interfaces/accessibility_focus_ring_controller.mojom.h"
Qiang Xu4e5853d382018-01-09 07:21:0717#include "ash/public/interfaces/constants.mojom.h"
dmazzoniff86e3472016-06-03 19:52:3218#include "ash/root_window_controller.h"
pkotwicz04d5c892015-01-15 00:05:3619#include "ash/shell.h"
pkotwicz04d5c892015-01-15 00:05:3620#include "ash/sticky_keys/sticky_keys_controller.h"
[email protected]44beb032014-06-11 06:24:3721#include "base/callback.h"
22#include "base/callback_helpers.h"
plundbladcf1d08f2015-09-28 09:18:5823#include "base/command_line.h"
fdorayba121422016-12-23 19:51:4824#include "base/memory/ptr_util.h"
[email protected]1dfebfc2013-06-04 03:14:3225#include "base/memory/singleton.h"
asvitkineb56637512016-09-01 19:41:4026#include "base/metrics/histogram_macros.h"
[email protected]ab38d192013-12-13 11:38:5827#include "base/path_service.h"
mgiuca30f75882017-03-28 02:07:1928#include "base/strings/string_piece.h"
[email protected]2e5e0b12014-05-07 13:30:2029#include "base/strings/string_split.h"
30#include "base/strings/string_util.h"
[email protected]0aae2fe2013-07-05 07:04:4231#include "base/values.h"
[email protected]1dfebfc2013-06-04 03:14:3232#include "chrome/browser/accessibility/accessibility_extension_api.h"
33#include "chrome/browser/browser_process.h"
[email protected]fdf40f3e2013-07-11 23:55:4634#include "chrome/browser/chrome_notification_types.h"
dmazzoni337c5af2016-09-13 23:08:5735#include "chrome/browser/chromeos/accessibility/accessibility_extension_loader.h"
David Tseng8a5de492018-01-17 20:41:3736#include "chrome/browser/chromeos/accessibility/dictation_chromeos.h"
pkotwicz04d5c892015-01-15 00:05:3637#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
elichtenbergc4b4bf462017-02-28 20:48:1038#include "chrome/browser/chromeos/accessibility/switch_access_event_handler.h"
dmazzoni16d2dec2016-12-19 23:27:5739#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
James Cook696fb106a2017-08-17 21:50:4440#include "chrome/browser/chromeos/ash_config.h"
dmazzoni16d2dec2016-12-19 23:27:5741#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
[email protected]e6f20642013-06-11 17:05:4642#include "chrome/browser/chromeos/profiles/profile_helper.h"
plundbladcf1d08f2015-09-28 09:18:5843#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
[email protected]1dfebfc2013-06-04 03:14:3244#include "chrome/browser/extensions/extension_service.h"
[email protected]1dfebfc2013-06-04 03:14:3245#include "chrome/browser/profiles/profile.h"
46#include "chrome/browser/profiles/profile_manager.h"
Katie D6264a8e2018-02-07 02:32:2047#include "chrome/browser/speech/tts_controller.h"
Qiang Xudce8aeb2018-01-11 04:17:2848#include "chrome/browser/ui/singleton_tabs.h"
[email protected]ab38d192013-12-13 11:38:5849#include "chrome/common/chrome_paths.h"
[email protected]9848bf6c2014-05-09 12:34:0050#include "chrome/common/extensions/api/accessibility_private.h"
[email protected]dccba4f82014-05-29 00:52:5651#include "chrome/common/extensions/extension_constants.h"
[email protected]1dfebfc2013-06-04 03:14:3252#include "chrome/common/pref_names.h"
Qiang Xudce8aeb2018-01-11 04:17:2853#include "chrome/common/url_constants.h"
[email protected]b58d2f82014-08-09 05:36:1454#include "chrome/grit/browser_resources.h"
[email protected]ce89d9392013-12-11 21:05:2055#include "chromeos/audio/chromeos_sounds.h"
Dominic Mazzonic85a5c92017-08-31 18:53:3056#include "chromeos/chromeos_switches.h"
dtseng3a17f212017-03-25 08:58:5257#include "chromeos/dbus/dbus_thread_manager.h"
58#include "chromeos/dbus/power_manager_client.h"
brettwb1fc1b82016-02-02 00:19:0859#include "components/prefs/pref_member.h"
60#include "components/prefs/pref_service.h"
tbarziccd5ad222017-03-24 04:46:3161#include "components/session_manager/core/session_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3262#include "content/public/browser/browser_accessibility_state.h"
[email protected]8c79e3f2013-10-30 01:05:1463#include "content/public/browser/browser_thread.h"
Qiang Xu95eea572018-02-17 08:10:3164#include "content/public/browser/focused_node_details.h"
[email protected]9cf54f362013-07-01 07:28:1265#include "content/public/browser/notification_details.h"
[email protected]1dfebfc2013-06-04 03:14:3266#include "content/public/browser/notification_service.h"
[email protected]9cf54f362013-07-01 07:28:1267#include "content/public/browser/notification_source.h"
[email protected]1dfebfc2013-06-04 03:14:3268#include "content/public/browser/web_ui.h"
plundbladcf1d08f2015-09-28 09:18:5869#include "content/public/common/content_switches.h"
bend32292b2016-10-07 00:21:5870#include "content/public/common/service_manager_connection.h"
reillyga3acbc12014-11-11 23:17:1271#include "extensions/browser/extension_registry.h"
[email protected]e4452d32013-11-15 23:07:4172#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0873#include "extensions/common/extension_messages.h"
[email protected]1dfebfc2013-06-04 03:14:3274#include "extensions/common/extension_resource.h"
hanxi79f7a572015-03-09 20:46:5975#include "extensions/common/host_id.h"
Ken Rockot388ba4fc2018-02-10 17:23:4176#include "mash/public/mojom/launchable.mojom.h"
[email protected]12b0a842013-12-04 20:48:1377#include "media/audio/sounds/sounds_manager.h"
dtsengd50debe32016-12-29 06:23:3778#include "media/base/media_switches.h"
rockot734fb662016-10-15 16:41:3079#include "services/service_manager/public/cpp/connector.h"
Qiang Xuc4b05752018-02-13 20:10:2880#include "ui/accessibility/ax_enum_util.h"
jamescook2d60f032017-06-01 00:55:2181#include "ui/base/ime/chromeos/extension_ime_util.h"
[email protected]1dfebfc2013-06-04 03:14:3282#include "ui/base/resource/resource_bundle.h"
Scott Violet66193f72017-06-26 22:24:1883#include "ui/views/widget/widget.h"
jamescook9eb0f912017-02-03 19:13:3984#include "ui/views/widget/widget_observer.h"
Qiang Xudce8aeb2018-01-11 04:17:2885#include "url/gurl.h"
[email protected]1dfebfc2013-06-04 03:14:3286
[email protected]8c79e3f2013-10-30 01:05:1487using content::BrowserThread;
[email protected]8c79e3f2013-10-30 01:05:1488using extensions::api::braille_display_private::BrailleController;
89using extensions::api::braille_display_private::DisplayState;
[email protected]2e5e0b12014-05-07 13:30:2090using extensions::api::braille_display_private::KeyEvent;
plundbladcf1d08f2015-09-28 09:18:5891using extensions::api::braille_display_private::StubBrailleController;
[email protected]1dfebfc2013-06-04 03:14:3292
93namespace chromeos {
94
95namespace {
96
sadrulcdc2bb42016-07-13 19:44:5197// When this flag is set, system sounds will not be played.
Qiang Xu89af823e2017-12-05 04:04:4798constexpr char kAshDisableSystemSounds[] = "ash-disable-system-sounds";
sadrulcdc2bb42016-07-13 19:44:5199
Qiang Xu89af823e2017-12-05 04:04:47100static chromeos::AccessibilityManager* g_accessibility_manager = nullptr;
[email protected]1dfebfc2013-06-04 03:14:32101
Qiang Xu89af823e2017-12-05 04:04:47102static BrailleController* g_braille_controller_for_test = nullptr;
[email protected]8c79e3f2013-10-30 01:05:14103
104BrailleController* GetBrailleController() {
plundbladcf1d08f2015-09-28 09:18:58105 if (g_braille_controller_for_test)
106 return g_braille_controller_for_test;
107 // Don't use the real braille controller for tests to avoid automatically
108 // starting ChromeVox which confuses some tests.
109 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
Dominic Mazzonic85a5c92017-08-31 18:53:30110 if (command_line->HasSwitch(::switches::kTestType))
plundbladcf1d08f2015-09-28 09:18:58111 return StubBrailleController::GetInstance();
112 return BrailleController::GetInstance();
[email protected]8c79e3f2013-10-30 01:05:14113}
114
[email protected]1dfebfc2013-06-04 03:14:32115} // namespace
116
dmazzoni94a4f882015-11-13 05:46:52117class ChromeVoxPanelWidgetObserver : public views::WidgetObserver {
118 public:
119 ChromeVoxPanelWidgetObserver(views::Widget* widget,
120 AccessibilityManager* manager)
121 : widget_(widget), manager_(manager) {
122 widget_->AddObserver(this);
123 }
124
James Cook0c4f37ac02018-01-17 02:17:09125 ~ChromeVoxPanelWidgetObserver() override = default;
126
dmazzoni94a4f882015-11-13 05:46:52127 void OnWidgetClosing(views::Widget* widget) override {
128 CHECK_EQ(widget_, widget);
129 widget->RemoveObserver(this);
130 manager_->OnChromeVoxPanelClosing();
James Cook0c4f37ac02018-01-17 02:17:09131 // |this| is deleted.
dmazzoni94a4f882015-11-13 05:46:52132 }
133
134 void OnWidgetDestroying(views::Widget* widget) override {
135 CHECK_EQ(widget_, widget);
136 widget->RemoveObserver(this);
137 manager_->OnChromeVoxPanelDestroying();
James Cook0c4f37ac02018-01-17 02:17:09138 // |this| is deleted.
dmazzoni94a4f882015-11-13 05:46:52139 }
140
141 private:
142 views::Widget* widget_;
143 AccessibilityManager* manager_;
144
145 DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWidgetObserver);
146};
147
[email protected]1dfebfc2013-06-04 03:14:32148///////////////////////////////////////////////////////////////////////////////
149// AccessibilityStatusEventDetails
150
151AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03152 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32153 bool enabled,
jamescooka7f8dab2016-06-21 01:44:03154 ash::AccessibilityNotificationVisibility notify)
James Cook12ccadd2017-10-09 03:53:34155 : notification_type(notification_type), enabled(enabled), notify(notify) {}
[email protected]1dfebfc2013-06-04 03:14:32156
157///////////////////////////////////////////////////////////////////////////////
[email protected]0aae2fe2013-07-05 07:04:42158// AccessibilityManager::PrefHandler
159
160AccessibilityManager::PrefHandler::PrefHandler(const char* pref_path)
161 : pref_path_(pref_path) {}
162
163AccessibilityManager::PrefHandler::~PrefHandler() {}
164
165void AccessibilityManager::PrefHandler::HandleProfileChanged(
James Cook12ccadd2017-10-09 03:53:34166 Profile* previous_profile,
167 Profile* current_profile) {
[email protected]0aae2fe2013-07-05 07:04:42168 // Returns if the current profile is null.
169 if (!current_profile)
170 return;
171
172 // If the user set a pref value on the login screen and is now starting a
173 // session with a new profile, copy the pref value to the profile.
James Cook12ccadd2017-10-09 03:53:34174 if ((previous_profile && ProfileHelper::IsSigninProfile(previous_profile) &&
[email protected]0aae2fe2013-07-05 07:04:42175 current_profile->IsNewProfile() &&
176 !ProfileHelper::IsSigninProfile(current_profile)) ||
177 // Special case for Guest mode:
178 // Guest mode launches a guest-mode browser process before session starts,
179 // so the previous profile is null.
James Cook12ccadd2017-10-09 03:53:34180 (!previous_profile && current_profile->IsGuestSession())) {
[email protected]0aae2fe2013-07-05 07:04:42181 // Returns if the pref has not been set by the user.
James Cook12ccadd2017-10-09 03:53:34182 const PrefService::Preference* pref =
183 ProfileHelper::GetSigninProfile()->GetPrefs()->FindPreference(
184 pref_path_);
[email protected]0aae2fe2013-07-05 07:04:42185 if (!pref || !pref->IsUserControlled())
186 return;
187
188 // Copy the pref value from the signin screen.
189 const base::Value* value_on_login = pref->GetValue();
190 PrefService* user_prefs = current_profile->GetPrefs();
191 user_prefs->Set(pref_path_, *value_on_login);
192 }
193}
194
195///////////////////////////////////////////////////////////////////////////////
196//
[email protected]1dfebfc2013-06-04 03:14:32197// AccessibilityManager
198
199// static
200void AccessibilityManager::Initialize() {
201 CHECK(g_accessibility_manager == NULL);
202 g_accessibility_manager = new AccessibilityManager();
203}
204
205// static
206void AccessibilityManager::Shutdown() {
207 CHECK(g_accessibility_manager);
208 delete g_accessibility_manager;
209 g_accessibility_manager = NULL;
210}
211
212// static
213AccessibilityManager* AccessibilityManager::Get() {
214 return g_accessibility_manager;
215}
216
Qiang Xudce8aeb2018-01-11 04:17:28217// static
218void AccessibilityManager::ShowAccessibilityHelp(Browser* browser) {
219 ShowSingletonTab(browser, GURL(chrome::kChromeAccessibilityHelpURL));
220}
221
[email protected]d80f19302013-06-07 13:12:14222AccessibilityManager::AccessibilityManager()
223 : profile_(NULL),
James Cookc63b9fd2017-08-18 18:48:32224 large_cursor_pref_handler_(ash::prefs::kAccessibilityLargeCursorEnabled),
225 sticky_keys_pref_handler_(ash::prefs::kAccessibilityStickyKeysEnabled),
226 spoken_feedback_pref_handler_(
227 ash::prefs::kAccessibilitySpokenFeedbackEnabled),
228 high_contrast_pref_handler_(
229 ash::prefs::kAccessibilityHighContrastEnabled),
230 autoclick_pref_handler_(ash::prefs::kAccessibilityAutoclickEnabled),
231 autoclick_delay_pref_handler_(ash::prefs::kAccessibilityAutoclickDelayMs),
[email protected]ced247a2014-06-13 19:14:19232 virtual_keyboard_pref_handler_(
James Cookc63b9fd2017-08-18 18:48:32233 ash::prefs::kAccessibilityVirtualKeyboardEnabled),
234 mono_audio_pref_handler_(ash::prefs::kAccessibilityMonoAudioEnabled),
235 caret_highlight_pref_handler_(
236 ash::prefs::kAccessibilityCaretHighlightEnabled),
dmazzoni756089a22016-03-15 23:55:16237 cursor_highlight_pref_handler_(
James Cookc63b9fd2017-08-18 18:48:32238 ash::prefs::kAccessibilityCursorHighlightEnabled),
239 focus_highlight_pref_handler_(
240 ash::prefs::kAccessibilityFocusHighlightEnabled),
Qiang Xu7e7dd6b2018-03-06 05:27:51241 tap_dragging_pref_handler_(ash::prefs::kTapDraggingEnabled),
James Cookc63b9fd2017-08-18 18:48:32242 select_to_speak_pref_handler_(
243 ash::prefs::kAccessibilitySelectToSpeakEnabled),
244 switch_access_pref_handler_(
245 ash::prefs::kAccessibilitySwitchAccessEnabled),
Qiang(Joe) Xua0f644592017-12-01 02:16:50246 spoken_feedback_enabled_(false),
dmazzoni756089a22016-03-15 23:55:16247 select_to_speak_enabled_(false),
248 switch_access_enabled_(false),
jamescooka7f8dab2016-06-21 01:44:03249 spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE),
[email protected]a81b2c32014-03-28 06:35:01250 braille_display_connected_(false),
[email protected]2e5e0b12014-05-07 13:30:20251 scoped_braille_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51252 braille_ime_current_(false),
dmazzoni94a4f882015-11-13 05:46:52253 chromevox_panel_(nullptr),
dtsengfb6d7cd2016-01-20 23:00:13254 extension_registry_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51255 weak_ptr_factory_(this) {
[email protected]1dfebfc2013-06-04 03:14:32256 notification_registrar_.Add(this,
[email protected]093d9ba2013-07-23 19:26:21257 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
[email protected]e6f20642013-06-11 17:05:46258 content::NotificationService::AllSources());
259 notification_registrar_.Add(this,
Yuki Awanod59b6492017-07-28 00:52:11260 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
261 content::NotificationService::AllSources());
James Cook12ccadd2017-10-09 03:53:34262 notification_registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
[email protected]1dfebfc2013-06-04 03:14:32263 content::NotificationService::AllSources());
James Cook12ccadd2017-10-09 03:53:34264 notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
[email protected]1dfebfc2013-06-04 03:14:32265 content::NotificationService::AllSources());
David Tseng768d7982017-12-21 00:20:11266 notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
267 content::NotificationService::AllSources());
Qiang Xu95eea572018-02-17 08:10:31268 notification_registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
269 content::NotificationService::AllSources());
[email protected]1488a035f2014-03-28 21:12:07270 input_method::InputMethodManager::Get()->AddObserver(this);
tbarziccd5ad222017-03-24 04:46:31271 session_manager::SessionManager::Get()->AddObserver(this);
[email protected]1488a035f2014-03-28 21:12:07272
[email protected]12b0a842013-12-04 20:48:13273 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
[email protected]ce89d9392013-12-11 21:05:20274 media::SoundsManager* manager = media::SoundsManager::Get();
275 manager->Initialize(SOUND_SHUTDOWN,
276 bundle.GetRawDataResource(IDR_SOUND_SHUTDOWN_WAV));
277 manager->Initialize(
278 SOUND_SPOKEN_FEEDBACK_ENABLED,
279 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_ENABLED_WAV));
280 manager->Initialize(
281 SOUND_SPOKEN_FEEDBACK_DISABLED,
282 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_DISABLED_WAV));
[email protected]07f3ea92014-08-14 05:23:38283 manager->Initialize(SOUND_PASSTHROUGH,
284 bundle.GetRawDataResource(IDR_SOUND_PASSTHROUGH_WAV));
285 manager->Initialize(SOUND_EXIT_SCREEN,
286 bundle.GetRawDataResource(IDR_SOUND_EXIT_SCREEN_WAV));
287 manager->Initialize(SOUND_ENTER_SCREEN,
288 bundle.GetRawDataResource(IDR_SOUND_ENTER_SCREEN_WAV));
dmazzoni16d2dec2016-12-19 23:27:57289 manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH,
290 bundle.GetRawDataResource(
291 IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH_WAV));
292 manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
293 bundle.GetRawDataResource(
294 IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV));
David Tseng580f050e2017-09-05 21:18:41295 manager->Initialize(SOUND_TOUCH_TYPE,
296 bundle.GetRawDataResource(IDR_SOUND_TOUCH_TYPE_WAV));
dmazzoni337c5af2016-09-13 23:08:57297
298 base::FilePath resources_path;
299 if (!PathService::Get(chrome::DIR_RESOURCES, &resources_path))
300 NOTREACHED();
301 chromevox_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
302 extension_misc::kChromeVoxExtensionId,
303 resources_path.Append(extension_misc::kChromeVoxExtensionPath),
304 base::Bind(&AccessibilityManager::PostUnloadChromeVox,
305 weak_ptr_factory_.GetWeakPtr())));
dmazzoni5288b2612016-09-16 23:05:39306 select_to_speak_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
307 extension_misc::kSelectToSpeakExtensionId,
308 resources_path.Append(extension_misc::kSelectToSpeakExtensionPath),
Katie D6264a8e2018-02-07 02:32:20309 base::Bind(&AccessibilityManager::PostUnloadSelectToSpeak,
310 weak_ptr_factory_.GetWeakPtr())));
elichtenberg0746c1bd2017-02-22 07:59:15311 switch_access_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
312 extension_misc::kSwitchAccessExtensionId,
313 resources_path.Append(extension_misc::kSwitchAccessExtensionPath),
314 base::Closure()));
Qiang Xu4e5853d382018-01-09 07:21:07315
316 // Connect to ash's AccessibilityController interface.
317 content::ServiceManagerConnection::GetForProcess()
318 ->GetConnector()
319 ->BindInterface(ash::mojom::kServiceName, &accessibility_controller_);
Qiang Xu56a75812018-03-15 00:28:34320
321 // Connect to ash's AccessibilityFocusRingController interface.
322 content::ServiceManagerConnection::GetForProcess()
323 ->GetConnector()
324 ->BindInterface(ash::mojom::kServiceName,
325 &accessibility_focus_ring_controller_);
[email protected]1dfebfc2013-06-04 03:14:32326}
327
328AccessibilityManager::~AccessibilityManager() {
329 CHECK(this == g_accessibility_manager);
jamescooka7f8dab2016-06-21 01:44:03330 AccessibilityStatusEventDetails details(ACCESSIBILITY_MANAGER_SHUTDOWN, false,
331 ash::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03332 NotifyAccessibilityStatusChanged(details);
[email protected]1488a035f2014-03-28 21:12:07333 input_method::InputMethodManager::Get()->RemoveObserver(this);
tbarziccd5ad222017-03-24 04:46:31334 session_manager::SessionManager::Get()->RemoveObserver(this);
dmazzoni94a4f882015-11-13 05:46:52335
336 if (chromevox_panel_) {
James Cook769799b2018-03-12 16:59:04337 chromevox_panel_->CloseNow();
dmazzoni94a4f882015-11-13 05:46:52338 chromevox_panel_ = nullptr;
339 }
[email protected]1dfebfc2013-06-04 03:14:32340}
341
[email protected]c20122572013-12-16 20:35:58342bool AccessibilityManager::ShouldShowAccessibilityMenu() {
343 // If any of the loaded profiles has an accessibility feature turned on - or
344 // enforced to always show the menu - we return true to show the menu.
James Cookfc97f0a2017-08-16 20:05:35345 // NOTE: This includes the login screen profile, so if a feature is turned on
346 // at the login screen the menu will show even if the user has no features
347 // enabled inside the session. http://crbug.com/755631
[email protected]c20122572013-12-16 20:35:58348 std::vector<Profile*> profiles =
349 g_browser_process->profile_manager()->GetLoadedProfiles();
350 for (std::vector<Profile*>::iterator it = profiles.begin();
James Cook12ccadd2017-10-09 03:53:34351 it != profiles.end(); ++it) {
James Cookc63b9fd2017-08-18 18:48:32352 PrefService* prefs = (*it)->GetPrefs();
353 if (prefs->GetBoolean(ash::prefs::kAccessibilityStickyKeysEnabled) ||
354 prefs->GetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled) ||
355 prefs->GetBoolean(ash::prefs::kAccessibilitySpokenFeedbackEnabled) ||
Katie D6af68c5e2018-02-14 23:21:16356 prefs->GetBoolean(ash::prefs::kAccessibilitySelectToSpeakEnabled) ||
James Cookc63b9fd2017-08-18 18:48:32357 prefs->GetBoolean(ash::prefs::kAccessibilityHighContrastEnabled) ||
358 prefs->GetBoolean(ash::prefs::kAccessibilityAutoclickEnabled) ||
359 prefs->GetBoolean(ash::prefs::kShouldAlwaysShowAccessibilityMenu) ||
360 prefs->GetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled) ||
361 prefs->GetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled) ||
362 prefs->GetBoolean(ash::prefs::kAccessibilityMonoAudioEnabled) ||
363 prefs->GetBoolean(ash::prefs::kAccessibilityCaretHighlightEnabled) ||
364 prefs->GetBoolean(ash::prefs::kAccessibilityCursorHighlightEnabled) ||
365 prefs->GetBoolean(ash::prefs::kAccessibilityFocusHighlightEnabled) ||
Qiang Xu7e7dd6b2018-03-06 05:27:51366 prefs->GetBoolean(ash::prefs::kTapDraggingEnabled))
[email protected]c20122572013-12-16 20:35:58367 return true;
368 }
369 return false;
370}
371
James Cookfc97f0a2017-08-16 20:05:35372void AccessibilityManager::UpdateAlwaysShowMenuFromPref() {
373 if (!profile_)
374 return;
375
James Cook696fb106a2017-08-17 21:50:44376 // TODO(crbug.com/594887): Fix for mash by moving pref into ash.
377 if (GetAshConfig() == ash::Config::MASH)
378 return;
379
James Cookfc97f0a2017-08-16 20:05:35380 // Update system tray menu visibility.
James Cook08e91dc2018-03-08 18:53:19381 ash::Shell::Get()
382 ->accessibility_controller()
383 ->NotifyAccessibilityStatusChanged(ash::A11Y_NOTIFICATION_NONE);
James Cookfc97f0a2017-08-16 20:05:35384}
385
[email protected]8126b812013-06-06 03:49:17386void AccessibilityManager::EnableLargeCursor(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14387 if (!profile_)
388 return;
389
390 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32391 pref_service->SetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled,
392 enabled);
[email protected]d80f19302013-06-07 13:12:14393 pref_service->CommitPendingWrite();
394}
395
James Cook9f9ff79d32017-09-01 00:39:29396void AccessibilityManager::OnLargeCursorChanged() {
jamescooka7f8dab2016-06-21 01:44:03397 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_LARGE_CURSOR,
James Cook9f9ff79d32017-09-01 00:39:29398 IsLargeCursorEnabled(),
399 ash::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03400 NotifyAccessibilityStatusChanged(details);
[email protected]8126b812013-06-06 03:49:17401}
402
minch0bfec0b2017-04-10 17:50:09403bool AccessibilityManager::IsLargeCursorEnabled() const {
James Cook9f9ff79d32017-09-01 00:39:29404 return profile_ && profile_->GetPrefs()->GetBoolean(
405 ash::prefs::kAccessibilityLargeCursorEnabled);
[email protected]8126b812013-06-06 03:49:17406}
407
[email protected]93a534e2013-06-20 16:41:44408void AccessibilityManager::EnableStickyKeys(bool enabled) {
409 if (!profile_)
410 return;
411 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32412 pref_service->SetBoolean(ash::prefs::kAccessibilityStickyKeysEnabled,
413 enabled);
[email protected]93a534e2013-06-20 16:41:44414 pref_service->CommitPendingWrite();
415}
416
minch0bfec0b2017-04-10 17:50:09417bool AccessibilityManager::IsStickyKeysEnabled() const {
Qiang Xu67fbc7a2018-02-16 02:52:41418 return profile_ && profile_->GetPrefs()->GetBoolean(
419 ash::prefs::kAccessibilityStickyKeysEnabled);
[email protected]93a534e2013-06-20 16:41:44420}
421
Qiang Xu67fbc7a2018-02-16 02:52:41422void AccessibilityManager::OnStickyKeysChanged() {
minchd9d542482017-04-07 19:29:56423 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_STICKY_KEYS,
Qiang Xu67fbc7a2018-02-16 02:52:41424 IsStickyKeysEnabled(),
425 ash::A11Y_NOTIFICATION_NONE);
minchd9d542482017-04-07 19:29:56426 NotifyAccessibilityStatusChanged(details);
[email protected]93a534e2013-06-20 16:41:44427}
428
[email protected]1dfebfc2013-06-04 03:14:32429void AccessibilityManager::EnableSpokenFeedback(
430 bool enabled,
jamescooka7f8dab2016-06-21 01:44:03431 ash::AccessibilityNotificationVisibility notify) {
[email protected]1dfebfc2013-06-04 03:14:32432 if (!profile_)
433 return;
[email protected]5d2ea362013-12-13 08:10:18434
[email protected]d80f19302013-06-07 13:12:14435 spoken_feedback_notification_ = notify;
436
[email protected]1dfebfc2013-06-04 03:14:32437 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32438 pref_service->SetBoolean(ash::prefs::kAccessibilitySpokenFeedbackEnabled,
439 enabled);
[email protected]1dfebfc2013-06-04 03:14:32440 pref_service->CommitPendingWrite();
[email protected]d80f19302013-06-07 13:12:14441
jamescooka7f8dab2016-06-21 01:44:03442 spoken_feedback_notification_ = ash::A11Y_NOTIFICATION_NONE;
[email protected]d80f19302013-06-07 13:12:14443}
444
Qiang Xu8889e372018-01-12 02:04:42445void AccessibilityManager::OnSpokenFeedbackChanged() {
[email protected]d80f19302013-06-07 13:12:14446 if (!profile_)
447 return;
448
[email protected]ced247a2014-06-13 19:14:19449 const bool enabled = profile_->GetPrefs()->GetBoolean(
James Cookc63b9fd2017-08-18 18:48:32450 ash::prefs::kAccessibilitySpokenFeedbackEnabled);
[email protected]d80f19302013-06-07 13:12:14451
dmazzoni63199b12016-10-19 15:44:36452 if (enabled) {
453 chromevox_loader_->SetProfile(
454 profile_, base::Bind(&AccessibilityManager::PostSwitchChromeVoxProfile,
455 weak_ptr_factory_.GetWeakPtr()));
456 }
dmazzoni2c013202016-09-07 19:59:37457
Qiang(Joe) Xua0f644592017-12-01 02:16:50458 if (spoken_feedback_enabled_ == enabled)
459 return;
460
461 spoken_feedback_enabled_ = enabled;
462
James Cook12ccadd2017-10-09 03:53:34463 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
464 enabled,
465 spoken_feedback_notification_);
[email protected]d8edc9c2014-02-25 00:06:03466
467 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32468
[email protected]0e9504d2013-11-05 02:33:29469 if (enabled) {
dtseng4702f8e2017-01-11 18:54:12470 chromevox_loader_->Load(profile_,
dmazzoni337c5af2016-09-13 23:08:57471 base::Bind(&AccessibilityManager::PostLoadChromeVox,
472 weak_ptr_factory_.GetWeakPtr()));
[email protected]0e9504d2013-11-05 02:33:29473 } else {
dmazzoni337c5af2016-09-13 23:08:57474 chromevox_loader_->Unload();
[email protected]0e9504d2013-11-05 02:33:29475 }
[email protected]2e5e0b12014-05-07 13:30:20476 UpdateBrailleImeState();
[email protected]b0a2ce32013-07-23 15:24:53477}
478
minch0bfec0b2017-04-10 17:50:09479bool AccessibilityManager::IsSpokenFeedbackEnabled() const {
Qiang Xu8889e372018-01-12 02:04:42480 return profile_ && profile_->GetPrefs()->GetBoolean(
481 ash::prefs::kAccessibilitySpokenFeedbackEnabled);
[email protected]1dfebfc2013-06-04 03:14:32482}
483
[email protected]1dfebfc2013-06-04 03:14:32484void AccessibilityManager::EnableHighContrast(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14485 if (!profile_)
486 return;
487
488 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32489 pref_service->SetBoolean(ash::prefs::kAccessibilityHighContrastEnabled,
490 enabled);
[email protected]d80f19302013-06-07 13:12:14491 pref_service->CommitPendingWrite();
492}
493
James Cook5fbdccb2017-09-01 21:17:55494bool AccessibilityManager::IsHighContrastEnabled() const {
495 return profile_ && profile_->GetPrefs()->GetBoolean(
496 ash::prefs::kAccessibilityHighContrastEnabled);
497}
[email protected]d80f19302013-06-07 13:12:14498
James Cook5fbdccb2017-09-01 21:17:55499void AccessibilityManager::OnHighContrastChanged() {
[email protected]d8edc9c2014-02-25 00:06:03500 AccessibilityStatusEventDetails details(
James Cook5fbdccb2017-09-01 21:17:55501 ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE, IsHighContrastEnabled(),
jamescooka7f8dab2016-06-21 01:44:03502 ash::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03503 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32504}
505
[email protected]628b8902014-03-12 05:26:41506void AccessibilityManager::OnLocaleChanged() {
[email protected]d1d5f4f2013-06-14 07:17:09507 if (!profile_)
508 return;
509
510 if (!IsSpokenFeedbackEnabled())
511 return;
512
513 // If the system locale changes and spoken feedback is enabled,
514 // reload ChromeVox so that it switches its internal translations
515 // to the new language.
jamescooka7f8dab2016-06-21 01:44:03516 EnableSpokenFeedback(false, ash::A11Y_NOTIFICATION_NONE);
517 EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_NONE);
[email protected]d1d5f4f2013-06-14 07:17:09518}
519
yawanoca05a1af2017-01-25 02:38:17520void AccessibilityManager::OnViewFocusedInArc(
521 const gfx::Rect& bounds_in_screen) {
Qiang Xu95eea572018-02-17 08:10:31522 accessibility_controller_->SetFocusHighlightRect(bounds_in_screen);
yawanoca05a1af2017-01-25 02:38:17523}
524
sadrulcdc2bb42016-07-13 19:44:51525bool AccessibilityManager::PlayEarcon(int sound_key, PlaySoundOption option) {
[email protected]07f3ea92014-08-14 05:23:38526 DCHECK(sound_key < chromeos::SOUND_COUNT);
sadrulcdc2bb42016-07-13 19:44:51527 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
528 if (cl->HasSwitch(kAshDisableSystemSounds))
529 return false;
Qiang Xu89af823e2017-12-05 04:04:47530 if (option == PlaySoundOption::ONLY_IF_SPOKEN_FEEDBACK_ENABLED &&
David Tseng89850d12017-08-29 02:23:41531 !IsSpokenFeedbackEnabled()) {
sadrulcdc2bb42016-07-13 19:44:51532 return false;
533 }
534 return media::SoundsManager::Get()->Play(sound_key);
[email protected]07f3ea92014-08-14 05:23:38535}
536
dmazzonidf9a1e922017-04-13 05:10:44537void AccessibilityManager::OnTwoFingerTouchStart() {
dmazzonic613a562017-05-02 03:19:19538 if (!profile())
539 return;
540
dmazzonidf9a1e922017-04-13 05:10:44541 extensions::EventRouter* event_router =
542 extensions::EventRouter::Get(profile());
543 CHECK(event_router);
544
Jinho Bang341ce5b02018-01-17 22:46:03545 auto event_args = std::make_unique<base::ListValue>();
546 auto event = std::make_unique<extensions::Event>(
dmazzonidf9a1e922017-04-13 05:10:44547 extensions::events::ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_START,
548 extensions::api::accessibility_private::OnTwoFingerTouchStart::kEventName,
549 std::move(event_args));
550 event_router->BroadcastEvent(std::move(event));
551}
552
553void AccessibilityManager::OnTwoFingerTouchStop() {
dmazzonic613a562017-05-02 03:19:19554 if (!profile())
555 return;
556
dmazzonidf9a1e922017-04-13 05:10:44557 extensions::EventRouter* event_router =
558 extensions::EventRouter::Get(profile());
559 CHECK(event_router);
560
Jinho Bang341ce5b02018-01-17 22:46:03561 auto event_args = std::make_unique<base::ListValue>();
562 auto event = std::make_unique<extensions::Event>(
dmazzonidf9a1e922017-04-13 05:10:44563 extensions::events::ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_STOP,
564 extensions::api::accessibility_private::OnTwoFingerTouchStop::kEventName,
565 std::move(event_args));
566 event_router->BroadcastEvent(std::move(event));
567}
568
dmazzoni16d2dec2016-12-19 23:27:57569bool AccessibilityManager::ShouldToggleSpokenFeedbackViaTouch() {
dmazzoni200099c2017-01-31 23:21:40570#if 1
571 // Temporarily disabling this feature until UI feedback is fixed.
572 // http://crbug.com/662501
573 return false;
574#else
dmazzoni16d2dec2016-12-19 23:27:57575 policy::BrowserPolicyConnectorChromeOS* connector =
576 g_browser_process->platform_part()->browser_policy_connector_chromeos();
577 if (!connector)
578 return false;
579
580 if (!connector->IsEnterpriseManaged())
581 return false;
582
583 const policy::DeviceCloudPolicyManagerChromeOS* const
584 device_cloud_policy_manager = connector->GetDeviceCloudPolicyManager();
585 if (!device_cloud_policy_manager)
586 return false;
587
588 if (!device_cloud_policy_manager->IsRemoraRequisition())
589 return false;
590
591 KioskAppManager* manager = KioskAppManager::Get();
592 KioskAppManager::App app;
593 CHECK(manager->GetApp(manager->GetAutoLaunchApp(), &app));
594 return app.was_auto_launched_with_zero_delay;
dmazzoni200099c2017-01-31 23:21:40595#endif
dmazzoni16d2dec2016-12-19 23:27:57596}
597
598bool AccessibilityManager::PlaySpokenFeedbackToggleCountdown(int tick_count) {
599 return media::SoundsManager::Get()->Play(
600 tick_count % 2 ? SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH
601 : SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW);
602}
603
Qiang Xu9e12fa762017-12-19 03:27:49604void AccessibilityManager::HandleAccessibilityGesture(
Qiang Xuc4b05752018-02-13 20:10:28605 ax::mojom::Gesture gesture) {
dmazzoni82ef29a2016-05-10 23:37:51606 extensions::EventRouter* event_router =
607 extensions::EventRouter::Get(profile());
608 CHECK(event_router);
609
610 std::unique_ptr<base::ListValue> event_args(new base::ListValue());
Qiang Xuc4b05752018-02-13 20:10:28611 event_args->AppendString(ui::ToString(gesture));
dmazzoni82ef29a2016-05-10 23:37:51612 std::unique_ptr<extensions::Event> event(new extensions::Event(
613 extensions::events::ACCESSIBILITY_PRIVATE_ON_ACCESSIBILITY_GESTURE,
614 extensions::api::accessibility_private::OnAccessibilityGesture::
615 kEventName,
616 std::move(event_args)));
617 event_router->DispatchEventWithLazyListener(
618 extension_misc::kChromeVoxExtensionId, std::move(event));
619}
620
dmazzoniff86e3472016-06-03 19:52:32621void AccessibilityManager::SetTouchAccessibilityAnchorPoint(
622 const gfx::Point& anchor_point) {
dmazzoni50f65802017-06-28 18:19:39623 for (auto* rwc : ash::RootWindowController::root_window_controllers())
624 rwc->SetTouchAccessibilityAnchorPoint(anchor_point);
dmazzoniff86e3472016-06-03 19:52:32625}
626
[email protected]1c881562013-10-12 07:52:58627void AccessibilityManager::EnableAutoclick(bool enabled) {
628 if (!profile_)
629 return;
630
631 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32632 pref_service->SetBoolean(ash::prefs::kAccessibilityAutoclickEnabled, enabled);
[email protected]1c881562013-10-12 07:52:58633 pref_service->CommitPendingWrite();
634}
635
minch0bfec0b2017-04-10 17:50:09636bool AccessibilityManager::IsAutoclickEnabled() const {
Qiang Xud0f3be2e2018-01-08 12:48:18637 return profile_ && profile_->GetPrefs()->GetBoolean(
638 ash::prefs::kAccessibilityAutoclickEnabled);
[email protected]1c881562013-10-12 07:52:58639}
640
[email protected]e1b299b2014-01-29 23:53:41641void AccessibilityManager::EnableVirtualKeyboard(bool enabled) {
642 if (!profile_)
643 return;
644
645 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32646 pref_service->SetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled,
[email protected]ced247a2014-06-13 19:14:19647 enabled);
[email protected]e1b299b2014-01-29 23:53:41648 pref_service->CommitPendingWrite();
649}
650
minch0bfec0b2017-04-10 17:50:09651bool AccessibilityManager::IsVirtualKeyboardEnabled() const {
Qiang Xu67fbc7a2018-02-16 02:52:41652 return profile_ && profile_->GetPrefs()->GetBoolean(
653 ash::prefs::kAccessibilityVirtualKeyboardEnabled);
[email protected]e1b299b2014-01-29 23:53:41654}
655
Qiang Xu67fbc7a2018-02-16 02:52:41656void AccessibilityManager::OnVirtualKeyboardChanged() {
jamescooka7f8dab2016-06-21 01:44:03657 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_VIRTUAL_KEYBOARD,
Qiang Xu67fbc7a2018-02-16 02:52:41658 IsVirtualKeyboardEnabled(),
659 ash::A11Y_NOTIFICATION_NONE);
rsadama1104b82014-11-03 20:50:52660 NotifyAccessibilityStatusChanged(details);
[email protected]e1b299b2014-01-29 23:53:41661}
662
warx533c8f62016-04-12 01:19:43663void AccessibilityManager::EnableMonoAudio(bool enabled) {
664 if (!profile_)
665 return;
666
667 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32668 pref_service->SetBoolean(ash::prefs::kAccessibilityMonoAudioEnabled, enabled);
warx533c8f62016-04-12 01:19:43669 pref_service->CommitPendingWrite();
670}
671
minch0bfec0b2017-04-10 17:50:09672bool AccessibilityManager::IsMonoAudioEnabled() const {
Qiang Xu1ee98022017-11-21 19:52:55673 return profile_ && profile_->GetPrefs()->GetBoolean(
674 ash::prefs::kAccessibilityMonoAudioEnabled);
warx533c8f62016-04-12 01:19:43675}
676
Qiang Xu1ee98022017-11-21 19:52:55677void AccessibilityManager::OnMonoAudioChanged() {
jamescooka7f8dab2016-06-21 01:44:03678 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_MONO_AUDIO,
Qiang Xu1ee98022017-11-21 19:52:55679 IsMonoAudioEnabled(),
680 ash::A11Y_NOTIFICATION_NONE);
warx533c8f62016-04-12 01:19:43681 NotifyAccessibilityStatusChanged(details);
warx533c8f62016-04-12 01:19:43682}
683
Daniel Erat477c56d2017-12-13 21:42:54684void AccessibilityManager::SetDarkenScreen(bool darken) {
Qiang Xu4e5853d382018-01-09 07:21:07685 accessibility_controller_->SetDarkenScreen(darken);
Daniel Erat477c56d2017-12-13 21:42:54686}
687
dmazzoni756089a22016-03-15 23:55:16688void AccessibilityManager::SetCaretHighlightEnabled(bool enabled) {
689 if (!profile_)
690 return;
691
692 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32693 pref_service->SetBoolean(ash::prefs::kAccessibilityCaretHighlightEnabled,
694 enabled);
dmazzoni756089a22016-03-15 23:55:16695 pref_service->CommitPendingWrite();
696}
697
698bool AccessibilityManager::IsCaretHighlightEnabled() const {
Qiang Xu95eea572018-02-17 08:10:31699 return profile_ && profile_->GetPrefs()->GetBoolean(
700 ash::prefs::kAccessibilityCaretHighlightEnabled);
dmazzoni756089a22016-03-15 23:55:16701}
702
Qiang Xu95eea572018-02-17 08:10:31703void AccessibilityManager::OnCaretHighlightChanged() {
mincha0b24ab2017-03-31 22:16:01704 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_CARET_HIGHLIGHT,
Qiang Xu95eea572018-02-17 08:10:31705 IsCaretHighlightEnabled(),
706 ash::A11Y_NOTIFICATION_NONE);
mincha0b24ab2017-03-31 22:16:01707 NotifyAccessibilityStatusChanged(details);
dmazzoni756089a22016-03-15 23:55:16708}
709
710void AccessibilityManager::SetCursorHighlightEnabled(bool enabled) {
711 if (!profile_)
712 return;
713
714 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32715 pref_service->SetBoolean(ash::prefs::kAccessibilityCursorHighlightEnabled,
dmazzoni756089a22016-03-15 23:55:16716 enabled);
717 pref_service->CommitPendingWrite();
718}
719
720bool AccessibilityManager::IsCursorHighlightEnabled() const {
Qiang Xu95eea572018-02-17 08:10:31721 return profile_ && profile_->GetPrefs()->GetBoolean(
722 ash::prefs::kAccessibilityCursorHighlightEnabled);
dmazzoni756089a22016-03-15 23:55:16723}
724
Qiang Xu95eea572018-02-17 08:10:31725void AccessibilityManager::OnCursorHighlightChanged() {
mincha0b24ab2017-03-31 22:16:01726 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_CURSOR_HIGHLIGHT,
Qiang Xu95eea572018-02-17 08:10:31727 IsCursorHighlightEnabled(),
728 ash::A11Y_NOTIFICATION_NONE);
mincha0b24ab2017-03-31 22:16:01729 NotifyAccessibilityStatusChanged(details);
dmazzoni756089a22016-03-15 23:55:16730}
731
732void AccessibilityManager::SetFocusHighlightEnabled(bool enabled) {
733 if (!profile_)
734 return;
735
736 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32737 pref_service->SetBoolean(ash::prefs::kAccessibilityFocusHighlightEnabled,
738 enabled);
dmazzoni756089a22016-03-15 23:55:16739 pref_service->CommitPendingWrite();
740}
741
742bool AccessibilityManager::IsFocusHighlightEnabled() const {
Qiang Xu95eea572018-02-17 08:10:31743 return profile_ && profile_->GetPrefs()->GetBoolean(
744 ash::prefs::kAccessibilityFocusHighlightEnabled);
dmazzoni756089a22016-03-15 23:55:16745}
746
Qiang Xu95eea572018-02-17 08:10:31747void AccessibilityManager::OnFocusHighlightChanged() {
748 bool enabled = IsFocusHighlightEnabled();
dmazzoni756089a22016-03-15 23:55:16749
dmazzoni42e4b002016-06-08 20:58:42750 // Focus highlighting can't be on when spoken feedback is on, because
751 // ChromeVox does its own focus highlighting.
Qiang Xu95eea572018-02-17 08:10:31752 if (IsSpokenFeedbackEnabled())
dmazzoni42e4b002016-06-08 20:58:42753 enabled = false;
mincha0b24ab2017-03-31 22:16:01754 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_FOCUS_HIGHLIGHT,
755 enabled, ash::A11Y_NOTIFICATION_NONE);
756 NotifyAccessibilityStatusChanged(details);
dmazzoni756089a22016-03-15 23:55:16757}
758
minchd9d542482017-04-07 19:29:56759void AccessibilityManager::EnableTapDragging(bool enabled) {
760 if (!profile_)
761 return;
762
763 PrefService* pref_service = profile_->GetPrefs();
Qiang Xu7e7dd6b2018-03-06 05:27:51764 pref_service->SetBoolean(ash::prefs::kTapDraggingEnabled, enabled);
minchd9d542482017-04-07 19:29:56765 pref_service->CommitPendingWrite();
766}
767
minch0bfec0b2017-04-10 17:50:09768bool AccessibilityManager::IsTapDraggingEnabled() const {
Qiang Xu7e7dd6b2018-03-06 05:27:51769 return profile_ &&
770 profile_->GetPrefs()->GetBoolean(ash::prefs::kTapDraggingEnabled);
minchd9d542482017-04-07 19:29:56771}
772
Qiang Xu7e7dd6b2018-03-06 05:27:51773void AccessibilityManager::OnTapDraggingChanged() {
minchd9d542482017-04-07 19:29:56774 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_TAP_DRAGGING,
Qiang Xu7e7dd6b2018-03-06 05:27:51775 IsTapDraggingEnabled(),
776 ash::A11Y_NOTIFICATION_NONE);
minchd9d542482017-04-07 19:29:56777 NotifyAccessibilityStatusChanged(details);
minchd9d542482017-04-07 19:29:56778}
779
dmazzoni756089a22016-03-15 23:55:16780void AccessibilityManager::SetSelectToSpeakEnabled(bool enabled) {
781 if (!profile_)
782 return;
783
784 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32785 pref_service->SetBoolean(ash::prefs::kAccessibilitySelectToSpeakEnabled,
786 enabled);
dmazzoni756089a22016-03-15 23:55:16787 pref_service->CommitPendingWrite();
788}
789
790bool AccessibilityManager::IsSelectToSpeakEnabled() const {
791 return select_to_speak_enabled_;
792}
793
Katie D6af68c5e2018-02-14 23:21:16794void AccessibilityManager::OnSelectToSpeakChanged() {
dmazzoni756089a22016-03-15 23:55:16795 if (!profile_)
796 return;
797
798 const bool enabled = profile_->GetPrefs()->GetBoolean(
James Cookc63b9fd2017-08-18 18:48:32799 ash::prefs::kAccessibilitySelectToSpeakEnabled);
dmazzoni756089a22016-03-15 23:55:16800
801 if (select_to_speak_enabled_ == enabled)
802 return;
803 select_to_speak_enabled_ = enabled;
804
Katie D6af68c5e2018-02-14 23:21:16805 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK,
806 enabled, ash::A11Y_NOTIFICATION_NONE);
807 NotifyAccessibilityStatusChanged(details);
808
Katie Dektar0c0f37952017-12-18 18:35:33809 if (enabled)
dtseng4702f8e2017-01-11 18:54:12810 select_to_speak_loader_->Load(profile_, base::Closure() /* done_cb */);
Katie Dektar0c0f37952017-12-18 18:35:33811 else
dmazzoni5288b2612016-09-16 23:05:39812 select_to_speak_loader_->Unload();
dmazzoni756089a22016-03-15 23:55:16813}
814
815void AccessibilityManager::SetSwitchAccessEnabled(bool enabled) {
816 if (!profile_)
817 return;
818
819 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32820 pref_service->SetBoolean(ash::prefs::kAccessibilitySwitchAccessEnabled,
821 enabled);
dmazzoni756089a22016-03-15 23:55:16822 pref_service->CommitPendingWrite();
823}
824
825bool AccessibilityManager::IsSwitchAccessEnabled() const {
826 return switch_access_enabled_;
827}
828
829void AccessibilityManager::UpdateSwitchAccessFromPref() {
830 if (!profile_)
831 return;
832
833 const bool enabled = profile_->GetPrefs()->GetBoolean(
James Cookc63b9fd2017-08-18 18:48:32834 ash::prefs::kAccessibilitySwitchAccessEnabled);
dmazzoni756089a22016-03-15 23:55:16835
Dominic Mazzonic85a5c92017-08-31 18:53:30836 // The Switch Access setting is behind a flag. Don't enable the feature
837 // even if the preference is enabled, if the flag isn't also set.
838 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
839 if (!command_line->HasSwitch(
840 chromeos::switches::kEnableExperimentalAccessibilityFeatures)) {
841 if (enabled) {
842 LOG(WARNING) << "Switch access enabled but experimental accessibility "
843 << "features flag is not set.";
844 }
845 return;
846 }
847
dmazzoni756089a22016-03-15 23:55:16848 if (switch_access_enabled_ == enabled)
849 return;
850 switch_access_enabled_ = enabled;
851
elichtenberg0746c1bd2017-02-22 07:59:15852 if (enabled) {
853 switch_access_loader_->Load(profile_, base::Closure() /* done_cb */);
elichtenbergc4b4bf462017-02-28 20:48:10854 switch_access_event_handler_.reset(
855 new chromeos::SwitchAccessEventHandler());
elichtenberg0746c1bd2017-02-22 07:59:15856 } else {
857 switch_access_loader_->Unload();
elichtenbergc4b4bf462017-02-28 20:48:10858 switch_access_event_handler_.reset(nullptr);
elichtenberg0746c1bd2017-02-22 07:59:15859 }
dmazzoni756089a22016-03-15 23:55:16860}
861
[email protected]a81b2c32014-03-28 06:35:01862bool AccessibilityManager::IsBrailleDisplayConnected() const {
863 return braille_display_connected_;
864}
865
[email protected]8c79e3f2013-10-30 01:05:14866void AccessibilityManager::CheckBrailleState() {
[email protected]a81b2c32014-03-28 06:35:01867 BrailleController* braille_controller = GetBrailleController();
868 if (!scoped_braille_observer_.IsObserving(braille_controller))
869 scoped_braille_observer_.Add(braille_controller);
[email protected]8c79e3f2013-10-30 01:05:14870 BrowserThread::PostTaskAndReplyWithResult(
James Cook12ccadd2017-10-09 03:53:34871 BrowserThread::IO, FROM_HERE,
[email protected]a81b2c32014-03-28 06:35:01872 base::Bind(&BrailleController::GetDisplayState,
873 base::Unretained(braille_controller)),
[email protected]8c79e3f2013-10-30 01:05:14874 base::Bind(&AccessibilityManager::ReceiveBrailleDisplayState,
875 weak_ptr_factory_.GetWeakPtr()));
876}
877
878void AccessibilityManager::ReceiveBrailleDisplayState(
dcheng24002d02016-04-08 02:42:40879 std::unique_ptr<extensions::api::braille_display_private::DisplayState>
880 state) {
[email protected]2e5e0b12014-05-07 13:30:20881 OnBrailleDisplayStateChanged(*state);
882}
883
884void AccessibilityManager::UpdateBrailleImeState() {
885 if (!profile_)
886 return;
887 PrefService* pref_service = profile_->GetPrefs();
mgiuca30f75882017-03-28 02:07:19888 std::string preload_engines_str =
889 pref_service->GetString(prefs::kLanguagePreloadEngines);
890 std::vector<base::StringPiece> preload_engines = base::SplitStringPiece(
891 preload_engines_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
892 std::vector<base::StringPiece>::iterator it =
893 std::find(preload_engines.begin(), preload_engines.end(),
jamescook2d60f032017-06-01 00:55:21894 extension_ime_util::kBrailleImeEngineId);
[email protected]2e5e0b12014-05-07 13:30:20895 bool is_enabled = (it != preload_engines.end());
896 bool should_be_enabled =
Qiang Xu8889e372018-01-12 02:04:42897 (IsSpokenFeedbackEnabled() && braille_display_connected_);
[email protected]2e5e0b12014-05-07 13:30:20898 if (is_enabled == should_be_enabled)
899 return;
900 if (should_be_enabled)
jamescook2d60f032017-06-01 00:55:21901 preload_engines.push_back(extension_ime_util::kBrailleImeEngineId);
[email protected]2e5e0b12014-05-07 13:30:20902 else
903 preload_engines.erase(it);
904 pref_service->SetString(prefs::kLanguagePreloadEngines,
brettwd94a22142015-07-15 05:19:26905 base::JoinString(preload_engines, ","));
[email protected]2e5e0b12014-05-07 13:30:20906 braille_ime_current_ = false;
[email protected]8c79e3f2013-10-30 01:05:14907}
908
[email protected]1488a035f2014-03-28 21:12:07909// Overridden from InputMethodManager::Observer.
910void AccessibilityManager::InputMethodChanged(
911 input_method::InputMethodManager* manager,
alematef06730292015-05-12 21:36:07912 Profile* /* profile */,
[email protected]1488a035f2014-03-28 21:12:07913 bool show_message) {
[email protected]1488a035f2014-03-28 21:12:07914 // Sticky keys is implemented only in ash.
dpolukhin04e5b8092014-09-11 02:55:05915 // TODO(dpolukhin): support Athena, crbug.com/408733.
James Cook696fb106a2017-08-17 21:50:44916 if (GetAshConfig() != ash::Config::MASH) {
skycb4be5b2017-04-06 17:52:45917 ash::Shell::Get()->sticky_keys_controller()->SetModifiersEnabled(
riajiang4b626b972016-09-13 16:12:49918 manager->IsISOLevel5ShiftUsedByCurrentInputMethod(),
919 manager->IsAltGrUsedByCurrentInputMethod());
920 }
[email protected]2e5e0b12014-05-07 13:30:20921 const chromeos::input_method::InputMethodDescriptor descriptor =
[email protected]f0881cf2014-08-15 23:31:42922 manager->GetActiveIMEState()->GetCurrentInputMethod();
[email protected]2e5e0b12014-05-07 13:30:20923 braille_ime_current_ =
jamescook2d60f032017-06-01 00:55:21924 (descriptor.id() == extension_ime_util::kBrailleImeEngineId);
[email protected]1488a035f2014-03-28 21:12:07925}
[email protected]8c79e3f2013-10-30 01:05:14926
tbarziccd5ad222017-03-24 04:46:31927void AccessibilityManager::OnSessionStateChanged() {
James Cook0c4f37ac02018-01-17 02:17:09928 // Don't reload ChromeVox during shutdown. http://crrev.com/c/838180
929 if (app_terminating_)
930 return;
931
tbarziccd5ad222017-03-24 04:46:31932 if (!chromevox_panel_)
933 return;
934 if (chromevox_panel_->for_blocked_user_session() ==
935 session_manager::SessionManager::Get()->IsUserSessionBlocked()) {
936 return;
937 }
938
939 // If user session got blocked or unblocked, reload ChromeVox panel, as
940 // functionality available to the panel differs based on whether the user
941 // session is active (and unlocked) or not.
942 ReloadChromeVoxPanel();
943}
944
[email protected]1dfebfc2013-06-04 03:14:32945void AccessibilityManager::SetProfile(Profile* profile) {
Yuki Awanod59b6492017-07-28 00:52:11946 // Do nothing if this is called for the current profile. This can happen. For
947 // example, ChromeSessionManager fires both
948 // NOTIFICATION_LOGIN_USER_PROFILE_PREPARED and NOTIFICATION_SESSION_STARTED,
949 // and we are observing both events.
950 if (profile_ == profile)
951 return;
952
[email protected]1dfebfc2013-06-04 03:14:32953 pref_change_registrar_.reset();
[email protected]d1d5f4f2013-06-14 07:17:09954 local_state_pref_change_registrar_.reset();
[email protected]1dfebfc2013-06-04 03:14:32955
David Tseng8a5de492018-01-17 20:41:37956 // Clear all dictation state on profile change.
957 dictation_.reset();
958
[email protected]1dfebfc2013-06-04 03:14:32959 if (profile) {
[email protected]0aae2fe2013-07-05 07:04:42960 // TODO(yoshiki): Move following code to PrefHandler.
[email protected]1dfebfc2013-06-04 03:14:32961 pref_change_registrar_.reset(new PrefChangeRegistrar);
962 pref_change_registrar_->Init(profile->GetPrefs());
963 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32964 ash::prefs::kShouldAlwaysShowAccessibilityMenu,
James Cookfc97f0a2017-08-16 20:05:35965 base::Bind(&AccessibilityManager::UpdateAlwaysShowMenuFromPref,
966 base::Unretained(this)));
967 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32968 ash::prefs::kAccessibilityLargeCursorEnabled,
James Cook9f9ff79d32017-09-01 00:39:29969 base::Bind(&AccessibilityManager::OnLargeCursorChanged,
[email protected]8126b812013-06-06 03:49:17970 base::Unretained(this)));
971 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32972 ash::prefs::kAccessibilityLargeCursorDipSize,
James Cook9f9ff79d32017-09-01 00:39:29973 base::Bind(&AccessibilityManager::OnLargeCursorChanged,
yawanodc5533b32017-02-23 11:04:38974 base::Unretained(this)));
975 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32976 ash::prefs::kAccessibilityStickyKeysEnabled,
Qiang Xu67fbc7a2018-02-16 02:52:41977 base::Bind(&AccessibilityManager::OnStickyKeysChanged,
[email protected]93a534e2013-06-20 16:41:44978 base::Unretained(this)));
979 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32980 ash::prefs::kAccessibilitySpokenFeedbackEnabled,
Qiang Xu8889e372018-01-12 02:04:42981 base::Bind(&AccessibilityManager::OnSpokenFeedbackChanged,
[email protected]1dfebfc2013-06-04 03:14:32982 base::Unretained(this)));
983 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32984 ash::prefs::kAccessibilityHighContrastEnabled,
James Cook5fbdccb2017-09-01 21:17:55985 base::Bind(&AccessibilityManager::OnHighContrastChanged,
[email protected]1dfebfc2013-06-04 03:14:32986 base::Unretained(this)));
[email protected]1c881562013-10-12 07:52:58987 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32988 ash::prefs::kAccessibilityVirtualKeyboardEnabled,
Qiang Xu67fbc7a2018-02-16 02:52:41989 base::Bind(&AccessibilityManager::OnVirtualKeyboardChanged,
[email protected]e1b299b2014-01-29 23:53:41990 base::Unretained(this)));
dmazzoni756089a22016-03-15 23:55:16991 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32992 ash::prefs::kAccessibilityMonoAudioEnabled,
Qiang Xu1ee98022017-11-21 19:52:55993 base::Bind(&AccessibilityManager::OnMonoAudioChanged,
warx533c8f62016-04-12 01:19:43994 base::Unretained(this)));
995 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32996 ash::prefs::kAccessibilityCaretHighlightEnabled,
Qiang Xu95eea572018-02-17 08:10:31997 base::Bind(&AccessibilityManager::OnCaretHighlightChanged,
dmazzoni756089a22016-03-15 23:55:16998 base::Unretained(this)));
999 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:321000 ash::prefs::kAccessibilityCursorHighlightEnabled,
Qiang Xu95eea572018-02-17 08:10:311001 base::Bind(&AccessibilityManager::OnCursorHighlightChanged,
dmazzoni756089a22016-03-15 23:55:161002 base::Unretained(this)));
1003 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:321004 ash::prefs::kAccessibilityFocusHighlightEnabled,
Qiang Xu95eea572018-02-17 08:10:311005 base::Bind(&AccessibilityManager::OnFocusHighlightChanged,
dmazzoni756089a22016-03-15 23:55:161006 base::Unretained(this)));
1007 pref_change_registrar_->Add(
Qiang Xu7e7dd6b2018-03-06 05:27:511008 ash::prefs::kTapDraggingEnabled,
1009 base::Bind(&AccessibilityManager::OnTapDraggingChanged,
minchd9d542482017-04-07 19:29:561010 base::Unretained(this)));
1011 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:321012 ash::prefs::kAccessibilitySelectToSpeakEnabled,
Katie D6af68c5e2018-02-14 23:21:161013 base::Bind(&AccessibilityManager::OnSelectToSpeakChanged,
dmazzoni756089a22016-03-15 23:55:161014 base::Unretained(this)));
1015 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:321016 ash::prefs::kAccessibilitySwitchAccessEnabled,
dmazzoni756089a22016-03-15 23:55:161017 base::Bind(&AccessibilityManager::UpdateSwitchAccessFromPref,
1018 base::Unretained(this)));
[email protected]1dfebfc2013-06-04 03:14:321019
[email protected]d1d5f4f2013-06-14 07:17:091020 local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
1021 local_state_pref_change_registrar_->Init(g_browser_process->local_state());
1022 local_state_pref_change_registrar_->Add(
1023 prefs::kApplicationLocale,
[email protected]628b8902014-03-12 05:26:411024 base::Bind(&AccessibilityManager::OnLocaleChanged,
[email protected]d1d5f4f2013-06-14 07:17:091025 base::Unretained(this)));
1026
[email protected]1dfebfc2013-06-04 03:14:321027 content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback(
James Cook12ccadd2017-10-09 03:53:341028 base::Bind(&AccessibilityManager::UpdateChromeOSAccessibilityHistograms,
1029 base::Unretained(this)));
dmazzoni337c5af2016-09-13 23:08:571030
dmazzoni337c5af2016-09-13 23:08:571031 extensions::ExtensionRegistry* registry =
1032 extensions::ExtensionRegistry::Get(profile);
1033 if (!extension_registry_observer_.IsObserving(registry))
1034 extension_registry_observer_.Add(registry);
[email protected]1dfebfc2013-06-04 03:14:321035 }
1036
[email protected]0aae2fe2013-07-05 07:04:421037 large_cursor_pref_handler_.HandleProfileChanged(profile_, profile);
1038 spoken_feedback_pref_handler_.HandleProfileChanged(profile_, profile);
1039 high_contrast_pref_handler_.HandleProfileChanged(profile_, profile);
minchd9d542482017-04-07 19:29:561040 sticky_keys_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]1c881562013-10-12 07:52:581041 autoclick_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]84d652d2013-10-23 13:57:571042 autoclick_delay_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]42b471f2014-01-31 20:31:291043 virtual_keyboard_pref_handler_.HandleProfileChanged(profile_, profile);
warx533c8f62016-04-12 01:19:431044 mono_audio_pref_handler_.HandleProfileChanged(profile_, profile);
dmazzoni756089a22016-03-15 23:55:161045 caret_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1046 cursor_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1047 focus_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
minchd9d542482017-04-07 19:29:561048 tap_dragging_pref_handler_.HandleProfileChanged(profile_, profile);
dmazzoni756089a22016-03-15 23:55:161049 select_to_speak_pref_handler_.HandleProfileChanged(profile_, profile);
1050 switch_access_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]0aae2fe2013-07-05 07:04:421051
[email protected]a81b2c32014-03-28 06:35:011052 bool had_profile = (profile_ != NULL);
1053 profile_ = profile;
1054
1055 if (!had_profile && profile)
[email protected]8c79e3f2013-10-30 01:05:141056 CheckBrailleState();
[email protected]2e5e0b12014-05-07 13:30:201057 else
1058 UpdateBrailleImeState();
James Cookfc97f0a2017-08-16 20:05:351059 UpdateAlwaysShowMenuFromPref();
dmazzoni756089a22016-03-15 23:55:161060 UpdateSwitchAccessFromPref();
dmazzoni39d6d4b2016-03-29 22:18:001061
Qiang Xu8889e372018-01-12 02:04:421062 // TODO(warx): reconcile to ash once the prefs registration above is moved to
1063 // ash.
1064 OnSpokenFeedbackChanged();
Katie D6af68c5e2018-02-14 23:21:161065 OnSelectToSpeakChanged();
[email protected]1dfebfc2013-06-04 03:14:321066}
1067
xiyuan5d8d3ba2017-03-01 21:34:401068void AccessibilityManager::ActiveUserChanged(
1069 const user_manager::User* active_user) {
xiyuan8c6a4112017-06-19 21:03:491070 if (active_user && active_user->is_profile_created())
1071 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]c20122572013-12-16 20:35:581072}
1073
[email protected]ce89d9392013-12-11 21:05:201074base::TimeDelta AccessibilityManager::PlayShutdownSound() {
Qiang Xu89af823e2017-12-05 04:04:471075 if (!PlayEarcon(SOUND_SHUTDOWN,
1076 PlaySoundOption::ONLY_IF_SPOKEN_FEEDBACK_ENABLED)) {
[email protected]4f011f12014-01-15 08:22:451077 return base::TimeDelta();
Qiang Xu89af823e2017-12-05 04:04:471078 }
[email protected]4f011f12014-01-15 08:22:451079 return media::SoundsManager::Get()->GetDuration(SOUND_SHUTDOWN);
[email protected]ce89d9392013-12-11 21:05:201080}
1081
dcheng24002d02016-04-08 02:42:401082std::unique_ptr<AccessibilityStatusSubscription>
1083AccessibilityManager::RegisterCallback(const AccessibilityStatusCallback& cb) {
[email protected]d8edc9c2014-02-25 00:06:031084 return callback_list_.Add(cb);
1085}
1086
1087void AccessibilityManager::NotifyAccessibilityStatusChanged(
Qiang Xu56a75812018-03-15 00:28:341088 const AccessibilityStatusEventDetails& details) {
[email protected]d8edc9c2014-02-25 00:06:031089 callback_list_.Notify(details);
James Cookfc97f0a2017-08-16 20:05:351090
James Cook696fb106a2017-08-17 21:50:441091 // TODO(crbug.com/594887): Fix for mash by moving pref into ash.
1092 if (GetAshConfig() == ash::Config::MASH)
1093 return;
1094
James Cookec144952017-09-01 00:05:161095 // Update system tray menu visibility. Prefs tracked inside ash handle their
1096 // own updates to avoid race conditions (pref updates are asynchronous between
1097 // chrome and ash).
Qiang Xu7e7dd6b2018-03-06 05:27:511098 if (details.notification_type == ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER) {
James Cook08e91dc2018-03-08 18:53:191099 ash::Shell::Get()
1100 ->accessibility_controller()
1101 ->NotifyAccessibilityStatusChanged(details.notify);
James Cookfc97f0a2017-08-16 20:05:351102 }
[email protected]d8edc9c2014-02-25 00:06:031103}
1104
[email protected]1dfebfc2013-06-04 03:14:321105void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
1106 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
1107 IsSpokenFeedbackEnabled());
1108 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast",
1109 IsHighContrastEnabled());
1110 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard",
[email protected]e1b299b2014-01-29 23:53:411111 IsVirtualKeyboardEnabled());
[email protected]7fb7ea42014-02-12 21:19:311112 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
[email protected]1dfebfc2013-06-04 03:14:321113 if (MagnificationManager::Get()) {
James Cookdb81c7672017-08-30 15:18:241114 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosScreenMagnifier",
1115 MagnificationManager::Get()->IsMagnifierEnabled());
[email protected]1dfebfc2013-06-04 03:14:321116 }
[email protected]ca3a0a82013-06-18 06:52:121117 if (profile_) {
1118 const PrefService* const prefs = profile_->GetPrefs();
yawano0c3441c72017-04-11 01:09:161119
1120 bool large_cursor_enabled =
James Cookc63b9fd2017-08-18 18:48:321121 prefs->GetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled);
yawano0c3441c72017-04-11 01:09:161122 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosLargeCursor",
1123 large_cursor_enabled);
yawano92daff52017-04-21 06:34:281124 if (large_cursor_enabled) {
yawano0c3441c72017-04-11 01:09:161125 UMA_HISTOGRAM_COUNTS_100(
1126 "Accessibility.CrosLargeCursorSize",
James Cookc63b9fd2017-08-18 18:48:321127 prefs->GetInteger(ash::prefs::kAccessibilityLargeCursorDipSize));
yawano0c3441c72017-04-11 01:09:161128 }
1129
[email protected]ca3a0a82013-06-18 06:52:121130 UMA_HISTOGRAM_BOOLEAN(
1131 "Accessibility.CrosAlwaysShowA11yMenu",
James Cookc63b9fd2017-08-18 18:48:321132 prefs->GetBoolean(ash::prefs::kShouldAlwaysShowAccessibilityMenu));
[email protected]0b5a0d2b2013-10-30 03:43:401133
[email protected]ced247a2014-06-13 19:14:191134 bool autoclick_enabled =
James Cookc63b9fd2017-08-18 18:48:321135 prefs->GetBoolean(ash::prefs::kAccessibilityAutoclickEnabled);
[email protected]0b5a0d2b2013-10-30 03:43:401136 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
1137 if (autoclick_enabled) {
1138 // We only want to log the autoclick delay if the user has actually
1139 // enabled autoclick.
1140 UMA_HISTOGRAM_CUSTOM_TIMES(
1141 "Accessibility.CrosAutoclickDelay",
1142 base::TimeDelta::FromMilliseconds(
James Cookc63b9fd2017-08-18 18:48:321143 prefs->GetInteger(ash::prefs::kAccessibilityAutoclickDelayMs)),
[email protected]0b5a0d2b2013-10-30 03:43:401144 base::TimeDelta::FromMilliseconds(1),
James Cookc63b9fd2017-08-18 18:48:321145 base::TimeDelta::FromMilliseconds(3000), 50);
[email protected]0b5a0d2b2013-10-30 03:43:401146 }
[email protected]ca3a0a82013-06-18 06:52:121147 }
dmazzoni756089a22016-03-15 23:55:161148 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCaretHighlight",
1149 IsCaretHighlightEnabled());
1150 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCursorHighlight",
1151 IsCursorHighlightEnabled());
1152 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosFocusHighlight",
1153 IsFocusHighlightEnabled());
1154 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSelectToSpeak",
1155 IsSelectToSpeakEnabled());
1156 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccess",
1157 IsSwitchAccessEnabled());
[email protected]1dfebfc2013-06-04 03:14:321158}
1159
1160void AccessibilityManager::Observe(
1161 int type,
1162 const content::NotificationSource& source,
1163 const content::NotificationDetails& details) {
1164 switch (type) {
[email protected]093d9ba2013-07-23 19:26:211165 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
[email protected]9cf54f362013-07-01 07:28:121166 // Update |profile_| when entering the login screen.
[email protected]c20122572013-12-16 20:35:581167 Profile* profile = ProfileManager::GetActiveUserProfile();
[email protected]d888cdc2013-06-24 17:06:201168 if (ProfileHelper::IsSigninProfile(profile))
1169 SetProfile(profile);
[email protected]1dfebfc2013-06-04 03:14:321170 break;
[email protected]d888cdc2013-06-24 17:06:201171 }
Yuki Awanod59b6492017-07-28 00:52:111172 case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED:
1173 // Update |profile_| when login user profile is prepared.
1174 // NOTIFICATION_SESSION_STARTED is not fired from UserSessionManager, but
1175 // profile may be changed by UserSessionManager in OOBE flow.
1176 SetProfile(ProfileManager::GetActiveUserProfile());
1177 break;
[email protected]e6f20642013-06-11 17:05:461178 case chrome::NOTIFICATION_SESSION_STARTED:
1179 // Update |profile_| when entering a session.
[email protected]c20122572013-12-16 20:35:581180 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]0e9504d2013-11-05 02:33:291181
[email protected]c20122572013-12-16 20:35:581182 // Add a session state observer to be able to monitor session changes.
xiyuan5d8d3ba2017-03-01 21:34:401183 if (!session_state_observer_.get())
[email protected]c20122572013-12-16 20:35:581184 session_state_observer_.reset(
xiyuan5d8d3ba2017-03-01 21:34:401185 new user_manager::ScopedUserSessionStateObserver(this));
[email protected]1dfebfc2013-06-04 03:14:321186 break;
[email protected]1dfebfc2013-06-04 03:14:321187 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
[email protected]e6f20642013-06-11 17:05:461188 // Update |profile_| when exiting a session or shutting down.
1189 Profile* profile = content::Source<Profile>(source).ptr();
1190 if (profile_ == profile)
1191 SetProfile(NULL);
[email protected]1dfebfc2013-06-04 03:14:321192 break;
1193 }
David Tseng768d7982017-12-21 00:20:111194 case chrome::NOTIFICATION_APP_TERMINATING: {
James Cook0c4f37ac02018-01-17 02:17:091195 app_terminating_ = true;
David Tseng768d7982017-12-21 00:20:111196 break;
1197 }
Qiang Xu95eea572018-02-17 08:10:311198 case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
1199 content::FocusedNodeDetails* node_details =
1200 content::Details<content::FocusedNodeDetails>(details).ptr();
1201 accessibility_controller_->SetFocusHighlightRect(
1202 node_details->node_bounds_in_screen);
1203 break;
1204 }
[email protected]1dfebfc2013-06-04 03:14:321205 }
1206}
1207
[email protected]2e5e0b12014-05-07 13:30:201208void AccessibilityManager::OnBrailleDisplayStateChanged(
[email protected]8c79e3f2013-10-30 01:05:141209 const DisplayState& display_state) {
[email protected]a81b2c32014-03-28 06:35:011210 braille_display_connected_ = display_state.available;
Qiang Xu797a8e72018-01-21 11:19:081211 accessibility_controller_->BrailleDisplayStateChanged(
1212 braille_display_connected_);
[email protected]2e5e0b12014-05-07 13:30:201213 UpdateBrailleImeState();
[email protected]8c79e3f2013-10-30 01:05:141214}
[email protected]0e9504d2013-11-05 02:33:291215
[email protected]2e5e0b12014-05-07 13:30:201216void AccessibilityManager::OnBrailleKeyEvent(const KeyEvent& event) {
1217 // Ensure the braille IME is active on braille keyboard (dots) input.
1218 if ((event.command ==
1219 extensions::api::braille_display_private::KEY_COMMAND_DOTS) &&
1220 !braille_ime_current_) {
[email protected]f0881cf2014-08-15 23:31:421221 input_method::InputMethodManager::Get()
1222 ->GetActiveIMEState()
jamescook2d60f032017-06-01 00:55:211223 ->ChangeInputMethod(extension_ime_util::kBrailleImeEngineId,
[email protected]f0881cf2014-08-15 23:31:421224 false /* show_message */);
[email protected]2e5e0b12014-05-07 13:30:201225 }
1226}
1227
dtsengfb6d7cd2016-01-20 23:00:131228void AccessibilityManager::OnExtensionUnloaded(
1229 content::BrowserContext* browser_context,
1230 const extensions::Extension* extension,
limasdf0deef2042017-05-03 19:17:171231 extensions::UnloadedExtensionReason reason) {
dtsengfb6d7cd2016-01-20 23:00:131232 if (extension->id() == keyboard_listener_extension_id_) {
1233 keyboard_listener_extension_id_ = std::string();
1234 keyboard_listener_capture_ = false;
dtsengfb6d7cd2016-01-20 23:00:131235 }
1236}
1237
1238void AccessibilityManager::OnShutdown(extensions::ExtensionRegistry* registry) {
1239 extension_registry_observer_.Remove(registry);
1240}
1241
dmazzoni337c5af2016-09-13 23:08:571242void AccessibilityManager::PostLoadChromeVox() {
James Cook0c4f37ac02018-01-17 02:17:091243 // In browser_tests loading the ChromeVox extension can race with shutdown.
1244 // http://crbug.com/801700
1245 if (app_terminating_)
1246 return;
1247
[email protected]ee8bbd972014-02-03 06:52:471248 // Do any setup work needed immediately after ChromeVox actually loads.
sadrulcdc2bb42016-07-13 19:44:511249 PlayEarcon(SOUND_SPOKEN_FEEDBACK_ENABLED, PlaySoundOption::ALWAYS);
[email protected]0e9504d2013-11-05 02:33:291250
dtseng4702f8e2017-01-11 18:54:121251 extensions::EventRouter* event_router =
1252 extensions::EventRouter::Get(profile_);
1253 CHECK(event_router);
dtseng703a2042015-01-22 17:46:511254
dtseng4702f8e2017-01-11 18:54:121255 std::unique_ptr<base::ListValue> event_args(new base::ListValue());
1256 std::unique_ptr<extensions::Event> event(new extensions::Event(
1257 extensions::events::ACCESSIBILITY_PRIVATE_ON_INTRODUCE_CHROME_VOX,
1258 extensions::api::accessibility_private::OnIntroduceChromeVox::kEventName,
1259 std::move(event_args)));
1260 event_router->DispatchEventWithLazyListener(
1261 extension_misc::kChromeVoxExtensionId, std::move(event));
dmazzoni94a4f882015-11-13 05:46:521262
James Cook769799b2018-03-12 16:59:041263 if (!chromevox_panel_) {
tbarziccd5ad222017-03-24 04:46:311264 chromevox_panel_ = new ChromeVoxPanel(
1265 profile_,
1266 session_manager::SessionManager::Get()->IsUserSessionBlocked());
dmazzoni94a4f882015-11-13 05:46:521267 chromevox_panel_widget_observer_.reset(
1268 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1269 }
dtsengd50debe32016-12-29 06:23:371270
1271 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
Dominic Mazzonic85a5c92017-08-31 18:53:301272 ::switches::kEnableAudioFocus)) {
dtsengd50debe32016-12-29 06:23:371273 base::CommandLine::ForCurrentProcess()->AppendSwitch(
Dominic Mazzonic85a5c92017-08-31 18:53:301274 ::switches::kEnableAudioFocus);
dtsengd50debe32016-12-29 06:23:371275 }
[email protected]0e9504d2013-11-05 02:33:291276}
1277
dmazzoni337c5af2016-09-13 23:08:571278void AccessibilityManager::PostUnloadChromeVox() {
[email protected]9d6c91362013-12-07 21:56:271279 // Do any teardown work needed immediately after ChromeVox actually unloads.
sadrulcdc2bb42016-07-13 19:44:511280 PlayEarcon(SOUND_SPOKEN_FEEDBACK_DISABLED, PlaySoundOption::ALWAYS);
Qiang Xu89af823e2017-12-05 04:04:471281
dmazzonifb33d592014-10-30 19:26:541282 // Clear the accessibility focus ring.
Qiang Xu56a75812018-03-15 00:28:341283 SetFocusRing(std::vector<gfx::Rect>(),
1284 ash::mojom::FocusRingBehavior::PERSIST_FOCUS_RING);
dmazzoni337c5af2016-09-13 23:08:571285
1286 if (chromevox_panel_) {
1287 chromevox_panel_->Close();
1288 chromevox_panel_ = nullptr;
1289 }
dtseng3a17f212017-03-25 08:58:521290
1291 // In case the user darkened the screen, undarken it now.
Qiang Xu4e5853d382018-01-09 07:21:071292 SetDarkenScreen(false);
Katie D6264a8e2018-02-07 02:32:201293
1294 // Stop speech.
1295 TtsController::GetInstance()->Stop();
[email protected]9d6c91362013-12-07 21:56:271296}
1297
dmazzoni63199b12016-10-19 15:44:361298void AccessibilityManager::PostSwitchChromeVoxProfile() {
tbarziccd5ad222017-03-24 04:46:311299 ReloadChromeVoxPanel();
1300}
1301
1302void AccessibilityManager::ReloadChromeVoxPanel() {
dmazzoni63199b12016-10-19 15:44:361303 if (chromevox_panel_) {
James Cook769799b2018-03-12 16:59:041304 chromevox_panel_->CloseNow();
dmazzoni63199b12016-10-19 15:44:361305 chromevox_panel_ = nullptr;
1306 }
tbarziccd5ad222017-03-24 04:46:311307 chromevox_panel_ = new ChromeVoxPanel(
1308 profile_, session_manager::SessionManager::Get()->IsUserSessionBlocked());
dmazzoni63199b12016-10-19 15:44:361309 chromevox_panel_widget_observer_.reset(
1310 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1311}
1312
dmazzoni94a4f882015-11-13 05:46:521313void AccessibilityManager::OnChromeVoxPanelClosing() {
jamescook788b4fc2017-05-18 16:16:061314 chromevox_panel_widget_observer_.reset();
dmazzoni94a4f882015-11-13 05:46:521315 chromevox_panel_ = nullptr;
dmazzoni94a4f882015-11-13 05:46:521316}
1317
1318void AccessibilityManager::OnChromeVoxPanelDestroying() {
1319 chromevox_panel_widget_observer_.reset(nullptr);
1320 chromevox_panel_ = nullptr;
1321}
1322
Katie D6264a8e2018-02-07 02:32:201323void AccessibilityManager::PostUnloadSelectToSpeak() {
1324 // Do any teardown work needed immediately after Select-to-Speak actually
1325 // unloads.
1326
1327 // Clear the accessibility focus ring and highlight.
Qiang Xu56a75812018-03-15 00:28:341328 HideFocusRing();
1329 HideHighlights();
Katie D6264a8e2018-02-07 02:32:201330
1331 // Stop speech.
1332 TtsController::GetInstance()->Stop();
1333}
1334
dtsengfb6d7cd2016-01-20 23:00:131335void AccessibilityManager::SetKeyboardListenerExtensionId(
1336 const std::string& id,
1337 content::BrowserContext* context) {
1338 keyboard_listener_extension_id_ = id;
1339
1340 extensions::ExtensionRegistry* registry =
1341 extensions::ExtensionRegistry::Get(context);
1342 if (!extension_registry_observer_.IsObserving(registry) && !id.empty())
1343 extension_registry_observer_.Add(registry);
1344}
1345
elichtenberga108c8a2017-06-02 21:13:191346void AccessibilityManager::SetSwitchAccessKeys(const std::set<int>& key_codes) {
1347 if (switch_access_enabled_)
1348 switch_access_event_handler_->SetKeysToCapture(key_codes);
1349}
1350
David Tseng8a5de492018-01-17 20:41:371351void AccessibilityManager::ToggleDictation() {
1352 if (!profile_)
1353 return;
1354
1355 if (!dictation_.get())
1356 dictation_ = std::make_unique<DictationChromeos>(profile_);
1357
1358 dictation_->OnToggleDictation();
1359}
1360
Qiang Xu56a75812018-03-15 00:28:341361void AccessibilityManager::SetFocusRingColor(SkColor color) {
1362 accessibility_focus_ring_controller_->SetFocusRingColor(color);
1363}
1364
1365void AccessibilityManager::ResetFocusRingColor() {
1366 accessibility_focus_ring_controller_->ResetFocusRingColor();
1367}
1368
1369void AccessibilityManager::SetFocusRing(
1370 const std::vector<gfx::Rect>& rects_in_screen,
1371 ash::mojom::FocusRingBehavior focus_ring_behavior) {
1372 accessibility_focus_ring_controller_->SetFocusRing(rects_in_screen,
1373 focus_ring_behavior);
1374 if (focus_ring_observer_for_test_)
1375 focus_ring_observer_for_test_.Run();
1376}
1377
1378void AccessibilityManager::HideFocusRing() {
1379 accessibility_focus_ring_controller_->HideFocusRing();
1380 if (focus_ring_observer_for_test_)
1381 focus_ring_observer_for_test_.Run();
1382}
1383
1384void AccessibilityManager::SetHighlights(
1385 const std::vector<gfx::Rect>& rects_in_screen,
1386 SkColor color) {
1387 accessibility_focus_ring_controller_->SetHighlights(rects_in_screen, color);
1388}
1389
1390void AccessibilityManager::HideHighlights() {
1391 accessibility_focus_ring_controller_->HideHighlights();
1392}
1393
Qiang Xu797a8e72018-01-21 11:19:081394void AccessibilityManager::SetProfileForTest(Profile* profile) {
1395 SetProfile(profile);
1396}
1397
1398// static
1399void AccessibilityManager::SetBrailleControllerForTest(
1400 BrailleController* controller) {
1401 g_braille_controller_for_test = controller;
1402}
1403
1404void AccessibilityManager::FlushForTesting() {
1405 accessibility_controller_.FlushForTesting();
1406}
1407
Qiang Xu56a75812018-03-15 00:28:341408void AccessibilityManager::SetFocusRingObserverForTest(
1409 base::RepeatingCallback<void()> observer) {
1410 focus_ring_observer_for_test_ = observer;
1411}
1412
[email protected]1dfebfc2013-06-04 03:14:321413} // namespace chromeos