Revert of Rename isSystemLocationEnabled to isLocationEnabled. (patchset #1 id:1...
[chromium-blink-merge.git] / ash / system / tray_accessibility.cc
blobb3c09ea176fbc501e3b70146d21b10cde806a713
1 // Copyright (c) 2012 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.
5 #include "ash/system/tray_accessibility.h"
7 #include "ash/accessibility_delegate.h"
8 #include "ash/metrics/user_metrics_recorder.h"
9 #include "ash/session/session_state_delegate.h"
10 #include "ash/shell.h"
11 #include "ash/system/tray/hover_highlight_view.h"
12 #include "ash/system/tray/system_tray.h"
13 #include "ash/system/tray/system_tray_delegate.h"
14 #include "ash/system/tray/system_tray_notifier.h"
15 #include "ash/system/tray/tray_constants.h"
16 #include "ash/system/tray/tray_details_view.h"
17 #include "ash/system/tray/tray_item_more.h"
18 #include "ash/system/tray/tray_popup_label_button.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "grit/ash_resources.h"
21 #include "grit/ash_strings.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/gfx/image/image.h"
25 #include "ui/views/controls/image_view.h"
26 #include "ui/views/controls/label.h"
27 #include "ui/views/layout/box_layout.h"
28 #include "ui/views/widget/widget.h"
30 namespace ash {
31 namespace {
33 enum AccessibilityState {
34 A11Y_NONE = 0,
35 A11Y_SPOKEN_FEEDBACK = 1 << 0,
36 A11Y_HIGH_CONTRAST = 1 << 1,
37 A11Y_SCREEN_MAGNIFIER = 1 << 2,
38 A11Y_LARGE_CURSOR = 1 << 3,
39 A11Y_AUTOCLICK = 1 << 4,
40 A11Y_VIRTUAL_KEYBOARD = 1 << 5,
41 A11Y_BRAILLE_DISPLAY_CONNECTED = 1 << 6,
44 uint32 GetAccessibilityState() {
45 AccessibilityDelegate* delegate =
46 Shell::GetInstance()->accessibility_delegate();
47 uint32 state = A11Y_NONE;
48 if (delegate->IsSpokenFeedbackEnabled())
49 state |= A11Y_SPOKEN_FEEDBACK;
50 if (delegate->IsHighContrastEnabled())
51 state |= A11Y_HIGH_CONTRAST;
52 if (delegate->IsMagnifierEnabled())
53 state |= A11Y_SCREEN_MAGNIFIER;
54 if (delegate->IsLargeCursorEnabled())
55 state |= A11Y_LARGE_CURSOR;
56 if (delegate->IsAutoclickEnabled())
57 state |= A11Y_AUTOCLICK;
58 if (delegate->IsVirtualKeyboardEnabled())
59 state |= A11Y_VIRTUAL_KEYBOARD;
60 if (delegate->IsBrailleDisplayConnected())
61 state |= A11Y_BRAILLE_DISPLAY_CONNECTED;
62 return state;
65 user::LoginStatus GetCurrentLoginStatus() {
66 return Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
69 } // namespace
71 namespace tray {
73 class DefaultAccessibilityView : public TrayItemMore {
74 public:
75 explicit DefaultAccessibilityView(SystemTrayItem* owner)
76 : TrayItemMore(owner, true) {
77 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
78 SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK).
79 ToImageSkia());
80 base::string16 label = bundle.GetLocalizedString(
81 IDS_ASH_STATUS_TRAY_ACCESSIBILITY);
82 SetLabel(label);
83 SetAccessibleName(label);
84 set_id(test::kAccessibilityTrayItemViewId);
87 ~DefaultAccessibilityView() override {}
89 private:
90 DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityView);
93 ////////////////////////////////////////////////////////////////////////////////
94 // ash::tray::AccessibilityPopupView
96 AccessibilityPopupView::AccessibilityPopupView(SystemTrayItem* owner,
97 uint32 enabled_state_bits)
98 : TrayNotificationView(owner, IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK),
99 label_(CreateLabel(enabled_state_bits)) {
100 InitView(label_);
103 views::Label* AccessibilityPopupView::CreateLabel(uint32 enabled_state_bits) {
104 DCHECK((enabled_state_bits &
105 (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED)) != 0);
106 base::string16 text;
107 if (enabled_state_bits & A11Y_BRAILLE_DISPLAY_CONNECTED) {
108 text.append(l10n_util::GetStringUTF16(
109 IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED_BUBBLE));
111 if (enabled_state_bits & A11Y_SPOKEN_FEEDBACK) {
112 if (!text.empty())
113 text.append(base::ASCIIToUTF16(" "));
114 text.append(l10n_util::GetStringUTF16(
115 IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_BUBBLE));
117 views::Label* label = new views::Label(text);
118 label->SetMultiLine(true);
119 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
120 return label;
123 ////////////////////////////////////////////////////////////////////////////////
124 // ash::tray::AccessibilityDetailedView
126 AccessibilityDetailedView::AccessibilityDetailedView(
127 SystemTrayItem* owner, user::LoginStatus login) :
128 TrayDetailsView(owner),
129 spoken_feedback_view_(NULL),
130 high_contrast_view_(NULL),
131 screen_magnifier_view_(NULL),
132 large_cursor_view_(NULL),
133 help_view_(NULL),
134 settings_view_(NULL),
135 autoclick_view_(NULL),
136 virtual_keyboard_view_(NULL),
137 spoken_feedback_enabled_(false),
138 high_contrast_enabled_(false),
139 screen_magnifier_enabled_(false),
140 large_cursor_enabled_(false),
141 autoclick_enabled_(false),
142 virtual_keyboard_enabled_(false),
143 login_(login) {
145 Reset();
147 AppendAccessibilityList();
148 AppendHelpEntries();
149 CreateSpecialRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE, this);
151 Layout();
154 void AccessibilityDetailedView::AppendAccessibilityList() {
155 CreateScrollableList();
156 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
158 AccessibilityDelegate* delegate =
159 Shell::GetInstance()->accessibility_delegate();
160 spoken_feedback_enabled_ = delegate->IsSpokenFeedbackEnabled();
161 spoken_feedback_view_ = AddScrollListItem(
162 bundle.GetLocalizedString(
163 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK),
164 spoken_feedback_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
165 spoken_feedback_enabled_);
167 // Large Cursor item is shown only in Login screen.
168 if (login_ == user::LOGGED_IN_NONE) {
169 large_cursor_enabled_ = delegate->IsLargeCursorEnabled();
170 large_cursor_view_ = AddScrollListItem(
171 bundle.GetLocalizedString(
172 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR),
173 large_cursor_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
174 large_cursor_enabled_);
177 high_contrast_enabled_ = delegate->IsHighContrastEnabled();
178 high_contrast_view_ = AddScrollListItem(
179 bundle.GetLocalizedString(
180 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE),
181 high_contrast_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
182 high_contrast_enabled_);
183 screen_magnifier_enabled_ = delegate->IsMagnifierEnabled();
184 screen_magnifier_view_ = AddScrollListItem(
185 bundle.GetLocalizedString(
186 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER),
187 screen_magnifier_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
188 screen_magnifier_enabled_);
190 // Don't show autoclick option at login screen.
191 if (login_ != user::LOGGED_IN_NONE) {
192 autoclick_enabled_ = delegate->IsAutoclickEnabled();
193 autoclick_view_ = AddScrollListItem(
194 bundle.GetLocalizedString(
195 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK),
196 autoclick_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
197 autoclick_enabled_);
200 virtual_keyboard_enabled_ = delegate->IsVirtualKeyboardEnabled();
201 virtual_keyboard_view_ = AddScrollListItem(
202 bundle.GetLocalizedString(
203 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD),
204 virtual_keyboard_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
205 virtual_keyboard_enabled_);
208 void AccessibilityDetailedView::AppendHelpEntries() {
209 // Currently the help page requires a browser window.
210 // TODO(yoshiki): show this even on login/lock screen. crbug.com/158286
211 bool userAddingRunning = ash::Shell::GetInstance()
212 ->session_state_delegate()
213 ->IsInSecondaryLoginScreen();
215 if (login_ == user::LOGGED_IN_NONE ||
216 login_ == user::LOGGED_IN_LOCKED || userAddingRunning)
217 return;
219 views::View* bottom_row = new View();
220 views::BoxLayout* layout = new
221 views::BoxLayout(views::BoxLayout::kHorizontal,
222 kTrayMenuBottomRowPadding,
223 kTrayMenuBottomRowPadding,
224 kTrayMenuBottomRowPaddingBetweenItems);
225 layout->SetDefaultFlex(1);
226 bottom_row->SetLayoutManager(layout);
228 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
230 TrayPopupLabelButton* help = new TrayPopupLabelButton(
231 this,
232 bundle.GetLocalizedString(
233 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LEARN_MORE));
234 bottom_row->AddChildView(help);
235 help_view_ = help;
237 TrayPopupLabelButton* settings = new TrayPopupLabelButton(
238 this,
239 bundle.GetLocalizedString(
240 IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS));
241 bottom_row->AddChildView(settings);
242 settings_view_ = settings;
244 AddChildView(bottom_row);
247 HoverHighlightView* AccessibilityDetailedView::AddScrollListItem(
248 const base::string16& text,
249 gfx::Font::FontStyle style,
250 bool checked) {
251 HoverHighlightView* container = new HoverHighlightView(this);
252 container->AddCheckableLabel(text, style, checked);
253 scroll_content()->AddChildView(container);
254 return container;
257 void AccessibilityDetailedView::OnViewClicked(views::View* sender) {
258 AccessibilityDelegate* delegate =
259 Shell::GetInstance()->accessibility_delegate();
260 if (sender == footer()->content()) {
261 TransitionToDefaultView();
262 } else if (sender == spoken_feedback_view_) {
263 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
264 delegate->IsSpokenFeedbackEnabled() ?
265 ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK :
266 ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK);
267 delegate->ToggleSpokenFeedback(ui::A11Y_NOTIFICATION_NONE);
268 } else if (sender == high_contrast_view_) {
269 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
270 delegate->IsHighContrastEnabled() ?
271 ash::UMA_STATUS_AREA_DISABLE_HIGH_CONTRAST :
272 ash::UMA_STATUS_AREA_ENABLE_HIGH_CONTRAST);
273 delegate->ToggleHighContrast();
274 } else if (sender == screen_magnifier_view_) {
275 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
276 delegate->IsMagnifierEnabled() ?
277 ash::UMA_STATUS_AREA_DISABLE_MAGNIFIER :
278 ash::UMA_STATUS_AREA_ENABLE_MAGNIFIER);
279 delegate->SetMagnifierEnabled(!delegate->IsMagnifierEnabled());
280 } else if (large_cursor_view_ && sender == large_cursor_view_) {
281 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
282 delegate->IsLargeCursorEnabled() ?
283 ash::UMA_STATUS_AREA_DISABLE_LARGE_CURSOR :
284 ash::UMA_STATUS_AREA_ENABLE_LARGE_CURSOR);
285 delegate->SetLargeCursorEnabled(!delegate->IsLargeCursorEnabled());
286 } else if (autoclick_view_ && sender == autoclick_view_) {
287 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
288 delegate->IsAutoclickEnabled() ?
289 ash::UMA_STATUS_AREA_DISABLE_AUTO_CLICK :
290 ash::UMA_STATUS_AREA_ENABLE_AUTO_CLICK);
291 delegate->SetAutoclickEnabled(!delegate->IsAutoclickEnabled());
292 } else if (virtual_keyboard_view_ && sender == virtual_keyboard_view_) {
293 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
294 delegate->IsVirtualKeyboardEnabled() ?
295 ash::UMA_STATUS_AREA_DISABLE_VIRTUAL_KEYBOARD :
296 ash::UMA_STATUS_AREA_ENABLE_VIRTUAL_KEYBOARD);
297 delegate->SetVirtualKeyboardEnabled(!delegate->IsVirtualKeyboardEnabled());
301 void AccessibilityDetailedView::ButtonPressed(views::Button* sender,
302 const ui::Event& event) {
303 SystemTrayDelegate* tray_delegate =
304 Shell::GetInstance()->system_tray_delegate();
305 if (sender == help_view_)
306 tray_delegate->ShowAccessibilityHelp();
307 else if (sender == settings_view_)
308 tray_delegate->ShowAccessibilitySettings();
311 } // namespace tray
313 ////////////////////////////////////////////////////////////////////////////////
314 // ash::TrayAccessibility
316 TrayAccessibility::TrayAccessibility(SystemTray* system_tray)
317 : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_ACCESSIBILITY),
318 default_(NULL),
319 detailed_popup_(NULL),
320 detailed_menu_(NULL),
321 request_popup_view_state_(A11Y_NONE),
322 tray_icon_visible_(false),
323 login_(GetCurrentLoginStatus()),
324 previous_accessibility_state_(GetAccessibilityState()),
325 show_a11y_menu_on_lock_screen_(true) {
326 DCHECK(Shell::GetInstance()->delegate());
327 DCHECK(system_tray);
328 Shell::GetInstance()->system_tray_notifier()->AddAccessibilityObserver(this);
331 TrayAccessibility::~TrayAccessibility() {
332 Shell::GetInstance()->system_tray_notifier()->
333 RemoveAccessibilityObserver(this);
336 void TrayAccessibility::SetTrayIconVisible(bool visible) {
337 if (tray_view())
338 tray_view()->SetVisible(visible);
339 tray_icon_visible_ = visible;
342 tray::AccessibilityDetailedView* TrayAccessibility::CreateDetailedMenu() {
343 return new tray::AccessibilityDetailedView(this, login_);
346 bool TrayAccessibility::GetInitialVisibility() {
347 // Shows accessibility icon if any accessibility feature is enabled.
348 // Otherwise, doen't show it.
349 return GetAccessibilityState() != A11Y_NONE;
352 views::View* TrayAccessibility::CreateDefaultView(user::LoginStatus status) {
353 CHECK(default_ == NULL);
355 // Shows accessibility menu if:
356 // - on login screen (not logged in);
357 // - "Enable accessibility menu" on chrome://settings is checked;
358 // - or any of accessibility features is enabled
359 // Otherwise, not shows it.
360 AccessibilityDelegate* delegate =
361 Shell::GetInstance()->accessibility_delegate();
362 if (login_ != user::LOGGED_IN_NONE &&
363 !delegate->ShouldShowAccessibilityMenu() &&
364 // On login screen, keeps the initial visibility of the menu.
365 (status != user::LOGGED_IN_LOCKED || !show_a11y_menu_on_lock_screen_))
366 return NULL;
368 CHECK(default_ == NULL);
369 default_ = new tray::DefaultAccessibilityView(this);
371 return default_;
374 views::View* TrayAccessibility::CreateDetailedView(user::LoginStatus status) {
375 CHECK(detailed_popup_ == NULL);
376 CHECK(detailed_menu_ == NULL);
378 if (request_popup_view_state_) {
379 detailed_popup_ =
380 new tray::AccessibilityPopupView(this, request_popup_view_state_);
381 request_popup_view_state_ = A11Y_NONE;
382 return detailed_popup_;
383 } else {
384 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
385 ash::UMA_STATUS_AREA_DETAILED_ACCESSABILITY);
386 detailed_menu_ = CreateDetailedMenu();
387 return detailed_menu_;
391 void TrayAccessibility::DestroyDefaultView() {
392 default_ = NULL;
395 void TrayAccessibility::DestroyDetailedView() {
396 detailed_popup_ = NULL;
397 detailed_menu_ = NULL;
400 void TrayAccessibility::UpdateAfterLoginStatusChange(user::LoginStatus status) {
401 // Stores the a11y feature status on just entering the lock screen.
402 if (login_ != user::LOGGED_IN_LOCKED && status == user::LOGGED_IN_LOCKED)
403 show_a11y_menu_on_lock_screen_ = (GetAccessibilityState() != A11Y_NONE);
405 login_ = status;
406 SetTrayIconVisible(GetInitialVisibility());
409 void TrayAccessibility::OnAccessibilityModeChanged(
410 ui::AccessibilityNotificationVisibility notify) {
411 SetTrayIconVisible(GetInitialVisibility());
413 uint32 accessibility_state = GetAccessibilityState();
414 // We'll get an extra notification if a braille display is connected when
415 // spoken feedback wasn't already enabled. This is because the braille
416 // connection state is already updated when spoken feedback is enabled so
417 // that the notifications can be consolidated into one. Therefore, we
418 // return early if there's no change in the state that we keep track of.
419 if (accessibility_state == previous_accessibility_state_)
420 return;
421 // Contains bits for spoken feedback and braille display connected currently
422 // being enabled.
423 uint32 being_enabled =
424 (accessibility_state & ~previous_accessibility_state_) &
425 (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED);
426 if ((notify == ui::A11Y_NOTIFICATION_SHOW) && being_enabled != A11Y_NONE) {
427 // Shows popup if |notify| is true and the spoken feedback is being enabled.
428 request_popup_view_state_ = being_enabled;
429 PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false);
430 } else {
431 if (detailed_popup_)
432 detailed_popup_->GetWidget()->Close();
433 if (detailed_menu_)
434 detailed_menu_->GetWidget()->Close();
437 previous_accessibility_state_ = accessibility_state;
440 } // namespace ash