Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / ash / system / tray_accessibility.cc
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.
4
5 #include "ash/system/tray_accessibility.h"
6
7 #include "ash/accessibility_delegate.h"
8 #include "ash/metrics/user_metrics_recorder.h"
9 #include "ash/shell.h"
10 #include "ash/system/tray/hover_highlight_view.h"
11 #include "ash/system/tray/system_tray.h"
12 #include "ash/system/tray/system_tray_delegate.h"
13 #include "ash/system/tray/system_tray_notifier.h"
14 #include "ash/system/tray/tray_constants.h"
15 #include "ash/system/tray/tray_details_view.h"
16 #include "ash/system/tray/tray_item_more.h"
17 #include "ash/system/tray/tray_notification_view.h"
18 #include "ash/system/tray/tray_popup_label_button.h"
19 #include "grit/ash_resources.h"
20 #include "grit/ash_strings.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/gfx/image/image.h"
24 #include "ui/views/controls/image_view.h"
25 #include "ui/views/controls/label.h"
26 #include "ui/views/layout/box_layout.h"
27 #include "ui/views/widget/widget.h"
28
29 namespace ash {
30 namespace internal {
31
32 namespace {
33
34 enum AccessibilityState {
35   A11Y_NONE             = 0,
36   A11Y_SPOKEN_FEEDBACK  = 1 << 0,
37   A11Y_HIGH_CONTRAST    = 1 << 1,
38   A11Y_SCREEN_MAGNIFIER = 1 << 2,
39   A11Y_LARGE_CURSOR     = 1 << 3,
40   A11Y_AUTOCLICK        = 1 << 4,
41 };
42
43 uint32 GetAccessibilityState() {
44   AccessibilityDelegate* delegate =
45       Shell::GetInstance()->accessibility_delegate();
46   uint32 state = A11Y_NONE;
47   if (delegate->IsSpokenFeedbackEnabled())
48     state |= A11Y_SPOKEN_FEEDBACK;
49   if (delegate->IsHighContrastEnabled())
50     state |= A11Y_HIGH_CONTRAST;
51   if (delegate->IsMagnifierEnabled())
52     state |= A11Y_SCREEN_MAGNIFIER;
53   if (delegate->IsLargeCursorEnabled())
54     state |= A11Y_LARGE_CURSOR;
55   if (delegate->IsAutoclickEnabled())
56     state |= A11Y_AUTOCLICK;
57   return state;
58 }
59
60 user::LoginStatus GetCurrentLoginStatus() {
61   return Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
62 }
63
64 }  // namespace
65
66 namespace tray {
67
68 class DefaultAccessibilityView : public TrayItemMore {
69  public:
70   explicit DefaultAccessibilityView(SystemTrayItem* owner)
71       : TrayItemMore(owner, true) {
72     ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
73     SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK).
74                     ToImageSkia());
75     base::string16 label = bundle.GetLocalizedString(
76         IDS_ASH_STATUS_TRAY_ACCESSIBILITY);
77     SetLabel(label);
78     SetAccessibleName(label);
79   }
80
81   virtual ~DefaultAccessibilityView() {
82   }
83
84  private:
85   DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityView);
86 };
87
88 class AccessibilityPopupView : public TrayNotificationView {
89  public:
90   AccessibilityPopupView(SystemTrayItem* owner)
91       : TrayNotificationView(owner, IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK) {
92     InitView(GetLabel());
93   }
94
95  private:
96   views::Label* GetLabel() {
97     views::Label* label = new views::Label(
98         l10n_util::GetStringUTF16(
99             IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_BUBBLE));
100     label->SetMultiLine(true);
101     label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
102     return label;
103   }
104
105   DISALLOW_COPY_AND_ASSIGN(AccessibilityPopupView);
106 };
107
108 ////////////////////////////////////////////////////////////////////////////////
109 // ash::internal::tray::AccessibilityDetailedView
110
111 AccessibilityDetailedView::AccessibilityDetailedView(
112     SystemTrayItem* owner, user::LoginStatus login) :
113         TrayDetailsView(owner),
114         spoken_feedback_view_(NULL),
115         high_contrast_view_(NULL),
116         screen_magnifier_view_(NULL),
117         large_cursor_view_(NULL),
118         help_view_(NULL),
119         settings_view_(NULL),
120         autoclick_view_(NULL),
121         spoken_feedback_enabled_(false),
122         high_contrast_enabled_(false),
123         screen_magnifier_enabled_(false),
124         large_cursor_enabled_(false),
125         autoclick_enabled_(false),
126         login_(login) {
127
128   Reset();
129
130   AppendAccessibilityList();
131   AppendHelpEntries();
132   CreateSpecialRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE, this);
133
134   Layout();
135 }
136
137 void AccessibilityDetailedView::AppendAccessibilityList() {
138   CreateScrollableList();
139   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
140
141   AccessibilityDelegate* delegate =
142       Shell::GetInstance()->accessibility_delegate();
143   spoken_feedback_enabled_ = delegate->IsSpokenFeedbackEnabled();
144   spoken_feedback_view_ = AddScrollListItem(
145       bundle.GetLocalizedString(
146           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK),
147       spoken_feedback_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
148       spoken_feedback_enabled_);
149
150   // Large Cursor item is shown only in Login screen.
151   if (login_ == user::LOGGED_IN_NONE) {
152     large_cursor_enabled_ = delegate->IsLargeCursorEnabled();
153     large_cursor_view_ = AddScrollListItem(
154         bundle.GetLocalizedString(
155             IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR),
156         large_cursor_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
157         large_cursor_enabled_);
158   }
159
160   high_contrast_enabled_ = delegate->IsHighContrastEnabled();
161   high_contrast_view_ = AddScrollListItem(
162       bundle.GetLocalizedString(
163           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE),
164       high_contrast_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
165       high_contrast_enabled_);
166   screen_magnifier_enabled_ = delegate->IsMagnifierEnabled();
167   screen_magnifier_view_ = AddScrollListItem(
168       bundle.GetLocalizedString(
169           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER),
170       screen_magnifier_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
171       screen_magnifier_enabled_);
172
173   // Don't show autoclick option at login screen.
174   if (login_ != user::LOGGED_IN_NONE) {
175     autoclick_enabled_ = delegate->IsAutoclickEnabled();
176     autoclick_view_ = AddScrollListItem(
177         bundle.GetLocalizedString(
178             IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK),
179         autoclick_enabled_ ? gfx::Font::BOLD : gfx::Font::NORMAL,
180         autoclick_enabled_);
181   }
182 }
183
184 void AccessibilityDetailedView::AppendHelpEntries() {
185   // Currently the help page requires a browser window.
186   // TODO(yoshiki): show this even on login/lock screen. crbug.com/158286
187   if (login_ == user::LOGGED_IN_NONE ||
188       login_ == user::LOGGED_IN_LOCKED)
189     return;
190
191   views::View* bottom_row = new View();
192   views::BoxLayout* layout = new
193       views::BoxLayout(views::BoxLayout::kHorizontal,
194                        kTrayMenuBottomRowPadding,
195                        kTrayMenuBottomRowPadding,
196                        kTrayMenuBottomRowPaddingBetweenItems);
197   layout->set_spread_blank_space(true);
198   bottom_row->SetLayoutManager(layout);
199
200   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
201
202   TrayPopupLabelButton* help = new TrayPopupLabelButton(
203       this,
204       bundle.GetLocalizedString(
205           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LEARN_MORE));
206   bottom_row->AddChildView(help);
207   help_view_ = help;
208
209   TrayPopupLabelButton* settings = new TrayPopupLabelButton(
210       this,
211       bundle.GetLocalizedString(
212           IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS));
213   bottom_row->AddChildView(settings);
214   settings_view_ = settings;
215
216   AddChildView(bottom_row);
217 }
218
219 HoverHighlightView* AccessibilityDetailedView::AddScrollListItem(
220     const base::string16& text,
221     gfx::Font::FontStyle style,
222     bool checked) {
223   HoverHighlightView* container = new HoverHighlightView(this);
224   container->AddCheckableLabel(text, style, checked);
225   scroll_content()->AddChildView(container);
226   return container;
227 }
228
229 void AccessibilityDetailedView::OnViewClicked(views::View* sender) {
230   AccessibilityDelegate* delegate =
231       Shell::GetInstance()->accessibility_delegate();
232   if (sender == footer()->content()) {
233     TransitionToDefaultView();
234   } else if (sender == spoken_feedback_view_) {
235     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
236         delegate->IsSpokenFeedbackEnabled() ?
237             ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK :
238             ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK);
239     delegate->ToggleSpokenFeedback(ash::A11Y_NOTIFICATION_NONE);
240   } else if (sender == high_contrast_view_) {
241     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
242         delegate->IsHighContrastEnabled() ?
243             ash::UMA_STATUS_AREA_DISABLE_HIGH_CONTRAST :
244             ash::UMA_STATUS_AREA_ENABLE_HIGH_CONTRAST);
245     delegate->ToggleHighContrast();
246   } else if (sender == screen_magnifier_view_) {
247     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
248         delegate->IsMagnifierEnabled() ?
249             ash::UMA_STATUS_AREA_DISABLE_MAGNIFIER :
250             ash::UMA_STATUS_AREA_ENABLE_MAGNIFIER);
251     delegate->SetMagnifierEnabled(!delegate->IsMagnifierEnabled());
252   } else if (large_cursor_view_ && sender == large_cursor_view_) {
253     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
254         delegate->IsLargeCursorEnabled() ?
255             ash::UMA_STATUS_AREA_DISABLE_LARGE_CURSOR :
256             ash::UMA_STATUS_AREA_ENABLE_LARGE_CURSOR);
257     delegate->SetLargeCursorEnabled(!delegate->IsLargeCursorEnabled());
258   } else if (autoclick_view_ && sender == autoclick_view_) {
259     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
260         delegate->IsAutoclickEnabled() ?
261             ash::UMA_STATUS_AREA_DISABLE_AUTO_CLICK :
262             ash::UMA_STATUS_AREA_ENABLE_AUTO_CLICK);
263     delegate->SetAutoclickEnabled(!delegate->IsAutoclickEnabled());
264   }
265 }
266
267 void AccessibilityDetailedView::ButtonPressed(views::Button* sender,
268                                               const ui::Event& event) {
269   SystemTrayDelegate* tray_delegate =
270       Shell::GetInstance()->system_tray_delegate();
271   if (sender == help_view_)
272     tray_delegate->ShowAccessibilityHelp();
273   else if (sender == settings_view_)
274     tray_delegate->ShowAccessibilitySettings();
275 }
276
277 }  // namespace tray
278
279 ////////////////////////////////////////////////////////////////////////////////
280 // ash::internal::TrayAccessibility
281
282 TrayAccessibility::TrayAccessibility(SystemTray* system_tray)
283     : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_ACCESSIBILITY),
284       default_(NULL),
285       detailed_popup_(NULL),
286       detailed_menu_(NULL),
287       request_popup_view_(false),
288       tray_icon_visible_(false),
289       login_(GetCurrentLoginStatus()),
290       previous_accessibility_state_(GetAccessibilityState()),
291       show_a11y_menu_on_lock_screen_(true) {
292   DCHECK(Shell::GetInstance()->delegate());
293   DCHECK(system_tray);
294   Shell::GetInstance()->system_tray_notifier()->AddAccessibilityObserver(this);
295 }
296
297 TrayAccessibility::~TrayAccessibility() {
298   Shell::GetInstance()->system_tray_notifier()->
299       RemoveAccessibilityObserver(this);
300 }
301
302 void TrayAccessibility::SetTrayIconVisible(bool visible) {
303   if (tray_view())
304     tray_view()->SetVisible(visible);
305   tray_icon_visible_ = visible;
306 }
307
308 tray::AccessibilityDetailedView* TrayAccessibility::CreateDetailedMenu() {
309   return new tray::AccessibilityDetailedView(this, login_);
310 }
311
312 bool TrayAccessibility::GetInitialVisibility() {
313   // Shows accessibility icon if any accessibility feature is enabled.
314   // Otherwise, doen't show it.
315   return GetAccessibilityState() != A11Y_NONE;
316 }
317
318 views::View* TrayAccessibility::CreateDefaultView(user::LoginStatus status) {
319   CHECK(default_ == NULL);
320
321   // Shows accessibility menu if:
322   // - on login screen (not logged in);
323   // - "Enable accessibility menu" on chrome://settings is checked;
324   // - or any of accessibility features is enabled
325   // Otherwise, not shows it.
326   AccessibilityDelegate* delegate =
327       Shell::GetInstance()->accessibility_delegate();
328   if (login_ != user::LOGGED_IN_NONE &&
329       !delegate->ShouldShowAccessibilityMenu() &&
330       // On login screen, keeps the initial visibility of the menu.
331       (status != user::LOGGED_IN_LOCKED || !show_a11y_menu_on_lock_screen_))
332     return NULL;
333
334   CHECK(default_ == NULL);
335   default_ = new tray::DefaultAccessibilityView(this);
336
337   return default_;
338 }
339
340 views::View* TrayAccessibility::CreateDetailedView(user::LoginStatus status) {
341   CHECK(detailed_popup_ == NULL);
342   CHECK(detailed_menu_ == NULL);
343
344   if (request_popup_view_) {
345     detailed_popup_ = new tray::AccessibilityPopupView(this);
346     request_popup_view_ = false;
347     return detailed_popup_;
348   } else {
349     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
350         ash::UMA_STATUS_AREA_DETAILED_ACCESSABILITY);
351     detailed_menu_ = CreateDetailedMenu();
352     return detailed_menu_;
353   }
354 }
355
356 void TrayAccessibility::DestroyDefaultView() {
357   default_ = NULL;
358 }
359
360 void TrayAccessibility::DestroyDetailedView() {
361   detailed_popup_ = NULL;
362   detailed_menu_ = NULL;
363 }
364
365 void TrayAccessibility::UpdateAfterLoginStatusChange(user::LoginStatus status) {
366   // Stores the a11y feature status on just entering the lock screen.
367   if (login_ != user::LOGGED_IN_LOCKED && status == user::LOGGED_IN_LOCKED)
368     show_a11y_menu_on_lock_screen_ = (GetAccessibilityState() != A11Y_NONE);
369
370   login_ = status;
371   SetTrayIconVisible(GetInitialVisibility());
372 }
373
374 void TrayAccessibility::OnAccessibilityModeChanged(
375     AccessibilityNotificationVisibility notify) {
376   SetTrayIconVisible(GetInitialVisibility());
377
378   uint32 accessibility_state = GetAccessibilityState();
379   if ((notify == ash::A11Y_NOTIFICATION_SHOW) &&
380       !(previous_accessibility_state_ & A11Y_SPOKEN_FEEDBACK) &&
381       (accessibility_state & A11Y_SPOKEN_FEEDBACK)) {
382     // Shows popup if |notify| is true and the spoken feedback is being enabled.
383     request_popup_view_ = true;
384     PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false);
385   } else {
386     if (detailed_popup_)
387       detailed_popup_->GetWidget()->Close();
388     if (detailed_menu_)
389       detailed_menu_->GetWidget()->Close();
390   }
391
392   previous_accessibility_state_ = accessibility_state;
393 }
394
395 }  // namespace internal
396 }  // namespace ash