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