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