Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1165)

Side by Side Diff: ash/system/tray_accessibility.cc

Issue 2838903002: Add accessibility related notification to notification center (Closed)
Patch Set: fix nits Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/system/tray_accessibility.h" 5 #include "ash/system/tray_accessibility.h"
6 6
7 #include "ash/accessibility_delegate.h" 7 #include "ash/accessibility_delegate.h"
8 #include "ash/accessibility_types.h" 8 #include "ash/accessibility_types.h"
9 #include "ash/resources/vector_icons/vector_icons.h" 9 #include "ash/resources/vector_icons/vector_icons.h"
10 #include "ash/session/session_controller.h" 10 #include "ash/session/session_controller.h"
11 #include "ash/session/session_state_delegate.h" 11 #include "ash/session/session_state_delegate.h"
12 #include "ash/shell.h" 12 #include "ash/shell.h"
13 #include "ash/shell_port.h" 13 #include "ash/shell_port.h"
14 #include "ash/strings/grit/ash_strings.h" 14 #include "ash/strings/grit/ash_strings.h"
15 #include "ash/system/system_notifier.h"
15 #include "ash/system/tray/hover_highlight_view.h" 16 #include "ash/system/tray/hover_highlight_view.h"
16 #include "ash/system/tray/system_tray.h" 17 #include "ash/system/tray/system_tray.h"
17 #include "ash/system/tray/system_tray_controller.h" 18 #include "ash/system/tray/system_tray_controller.h"
18 #include "ash/system/tray/system_tray_notifier.h" 19 #include "ash/system/tray/system_tray_notifier.h"
19 #include "ash/system/tray/tray_constants.h" 20 #include "ash/system/tray/tray_constants.h"
20 #include "ash/system/tray/tray_details_view.h" 21 #include "ash/system/tray/tray_details_view.h"
21 #include "ash/system/tray/tray_item_more.h" 22 #include "ash/system/tray/tray_item_more.h"
22 #include "ash/system/tray/tray_popup_item_style.h"
23 #include "ash/system/tray/tray_popup_utils.h" 23 #include "ash/system/tray/tray_popup_utils.h"
24 #include "ash/system/tray/tri_view.h" 24 #include "ash/system/tray/tri_view.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "ui/base/l10n/l10n_util.h" 25 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/gfx/image/image.h" 26 #include "ui/gfx/image/image.h"
29 #include "ui/gfx/paint_vector_icon.h" 27 #include "ui/gfx/paint_vector_icon.h"
28 #include "ui/gfx/vector_icon_types.h"
29 #include "ui/message_center/message_center.h"
30 #include "ui/native_theme/native_theme.h" 30 #include "ui/native_theme/native_theme.h"
31 #include "ui/resources/grit/ui_resources.h" 31 #include "ui/resources/grit/ui_resources.h"
32 #include "ui/views/background.h"
33 #include "ui/views/controls/button/custom_button.h"
34 #include "ui/views/controls/image_view.h"
35 #include "ui/views/controls/label.h"
36 #include "ui/views/controls/separator.h" 32 #include "ui/views/controls/separator.h"
37 #include "ui/views/layout/box_layout.h"
38 #include "ui/views/layout/grid_layout.h"
39 #include "ui/views/widget/widget.h" 33 #include "ui/views/widget/widget.h"
40 34
41 namespace ash { 35 namespace ash {
42 namespace { 36 namespace {
43 37
44 enum AccessibilityState { 38 enum AccessibilityState {
45 A11Y_NONE = 0, 39 A11Y_NONE = 0,
46 A11Y_SPOKEN_FEEDBACK = 1 << 0, 40 A11Y_SPOKEN_FEEDBACK = 1 << 0,
47 A11Y_HIGH_CONTRAST = 1 << 1, 41 A11Y_HIGH_CONTRAST = 1 << 1,
48 A11Y_SCREEN_MAGNIFIER = 1 << 2, 42 A11Y_SCREEN_MAGNIFIER = 1 << 2,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 state |= A11Y_STICKY_KEYS; 81 state |= A11Y_STICKY_KEYS;
88 if (delegate->IsTapDraggingEnabled()) 82 if (delegate->IsTapDraggingEnabled())
89 state |= A11Y_TAP_DRAGGING; 83 state |= A11Y_TAP_DRAGGING;
90 return state; 84 return state;
91 } 85 }
92 86
93 LoginStatus GetCurrentLoginStatus() { 87 LoginStatus GetCurrentLoginStatus() {
94 return Shell::Get()->session_controller()->login_status(); 88 return Shell::Get()->session_controller()->login_status();
95 } 89 }
96 90
91 // Returns notification icon based on the enabled accessibility state.
92 const gfx::VectorIcon& GetNotificationIcon(uint32_t enabled_accessibility) {
93 if (enabled_accessibility & A11Y_BRAILLE_DISPLAY_CONNECTED &&
James Cook 2017/05/16 00:56:18 optional: Consider () around (a & b). The operator
yiyix 2017/05/19 02:29:55 Updated, it's easier for readability.
94 enabled_accessibility & A11Y_SPOKEN_FEEDBACK) {
95 return ash::kSystemMenuAccessibilityIcon;
James Cook 2017/05/16 00:56:18 nit: ash:: not needed, here or below
yiyix 2017/05/19 02:29:55 would it be a good idea to remove all ash:: in thi
James Cook 2017/05/19 04:11:09 Yes, removing all ash:: is fine. We avoid extra na
96 } else {
James Cook 2017/05/16 00:56:19 nit: else not needed
yiyix 2017/05/19 02:29:56 Done.
97 if (enabled_accessibility & A11Y_BRAILLE_DISPLAY_CONNECTED)
98 return ash::kNotificationAccessibilityBrailleIcon;
99 else if (enabled_accessibility & A11Y_SPOKEN_FEEDBACK)
100 return ash::kSystemMenuAccessibilityChromevoxIcon;
101 else
102 return gfx::kNoneIcon;
103 }
104 }
105
97 } // namespace 106 } // namespace
98 107
99 namespace tray { 108 namespace tray {
100 109
101 class DefaultAccessibilityView : public TrayItemMore { 110 class DefaultAccessibilityView : public TrayItemMore {
102 public: 111 public:
103 explicit DefaultAccessibilityView(SystemTrayItem* owner) 112 explicit DefaultAccessibilityView(SystemTrayItem* owner)
104 : TrayItemMore(owner) { 113 : TrayItemMore(owner) {
105 base::string16 label = 114 base::string16 label =
106 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY); 115 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY);
(...skipping 11 matching lines...) Expand all
118 std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); 127 std::unique_ptr<TrayPopupItemStyle> style = CreateStyle();
119 SetImage(gfx::CreateVectorIcon(kSystemMenuAccessibilityIcon, 128 SetImage(gfx::CreateVectorIcon(kSystemMenuAccessibilityIcon,
120 style->GetIconColor())); 129 style->GetIconColor()));
121 } 130 }
122 131
123 private: 132 private:
124 DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityView); 133 DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityView);
125 }; 134 };
126 135
127 //////////////////////////////////////////////////////////////////////////////// 136 ////////////////////////////////////////////////////////////////////////////////
128 // ash::tray::AccessibilityPopupView
129
130 AccessibilityPopupView::AccessibilityPopupView(uint32_t enabled_state_bits)
131 : label_(CreateLabel(enabled_state_bits)) {}
132
133 void AccessibilityPopupView::Init() {
134 set_background(views::Background::CreateThemedSolidBackground(
135 this, ui::NativeTheme::kColorId_BubbleBackground));
136
137 views::GridLayout* layout = new views::GridLayout(this);
138 SetLayoutManager(layout);
139
140 views::ImageView* close_button = new views::ImageView();
141 close_button->SetImage(
142 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(IDR_MESSAGE_CLOSE));
143 close_button->SetHorizontalAlignment(views::ImageView::CENTER);
144 close_button->SetVerticalAlignment(views::ImageView::CENTER);
145
146 views::ImageView* icon = new views::ImageView;
147 icon->SetImage(
148 gfx::CreateVectorIcon(kSystemMenuAccessibilityIcon, kMenuIconColor));
149
150 views::ColumnSet* columns = layout->AddColumnSet(0);
151
152 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2);
153
154 // Icon
155 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
156 0, /* resize percent */
157 views::GridLayout::FIXED, kNotificationIconWidth,
158 kNotificationIconWidth);
159
160 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2);
161
162 // Contents
163 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
164 100, /* resize percent */
165 views::GridLayout::FIXED, kTrayNotificationContentsWidth,
166 kTrayNotificationContentsWidth);
167
168 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2);
169
170 // Close button
171 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING,
172 0, /* resize percent */
173 views::GridLayout::FIXED, kNotificationButtonWidth,
174 kNotificationButtonWidth);
175
176 // Layout rows
177 layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems);
178 layout->StartRow(0, 0);
179 layout->AddView(icon);
180 layout->AddView(label_);
181 layout->AddView(close_button);
182 layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems);
183 }
184
185 views::Label* AccessibilityPopupView::CreateLabel(uint32_t enabled_state_bits) {
186 DCHECK((enabled_state_bits &
187 (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED)) != 0);
188 base::string16 text;
189 if (enabled_state_bits & A11Y_BRAILLE_DISPLAY_CONNECTED) {
190 text.append(l10n_util::GetStringUTF16(
191 IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED_BUBBLE));
192 }
193 if (enabled_state_bits & A11Y_SPOKEN_FEEDBACK) {
194 if (!text.empty())
195 text.append(base::ASCIIToUTF16(" "));
196 text.append(l10n_util::GetStringUTF16(
197 IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_BUBBLE));
198 }
199 views::Label* label = new views::Label(text);
200 label->SetMultiLine(true);
201 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
202 return label;
203 }
204
205 ////////////////////////////////////////////////////////////////////////////////
206 // ash::tray::AccessibilityDetailedView 137 // ash::tray::AccessibilityDetailedView
207 138
208 AccessibilityDetailedView::AccessibilityDetailedView(SystemTrayItem* owner) 139 AccessibilityDetailedView::AccessibilityDetailedView(SystemTrayItem* owner)
209 : TrayDetailsView(owner) { 140 : TrayDetailsView(owner) {
210 Reset(); 141 Reset();
211 AppendAccessibilityList(); 142 AppendAccessibilityList();
212 CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE); 143 CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE);
213 Layout(); 144 Layout();
214 } 145 }
215 146
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 Shell::Get()->system_tray_controller()->ShowAccessibilityHelp(); 335 Shell::Get()->system_tray_controller()->ShowAccessibilityHelp();
405 owner()->system_tray()->CloseSystemBubble(); 336 owner()->system_tray()->CloseSystemBubble();
406 } 337 }
407 } 338 }
408 339
409 } // namespace tray 340 } // namespace tray
410 341
411 //////////////////////////////////////////////////////////////////////////////// 342 ////////////////////////////////////////////////////////////////////////////////
412 // ash::TrayAccessibility 343 // ash::TrayAccessibility
413 344
345 const char kNotificationId[] = "chrome://settings/accessibility";
James Cook 2017/05/16 00:56:18 Can this go in the anonymous namespace above?
yiyix 2017/05/19 02:29:56 Yea, i was not sure where to put it. it's just a p
346
414 TrayAccessibility::TrayAccessibility(SystemTray* system_tray) 347 TrayAccessibility::TrayAccessibility(SystemTray* system_tray)
415 : TrayImageItem(system_tray, 348 : TrayImageItem(system_tray,
416 kSystemTrayAccessibilityIcon, 349 kSystemTrayAccessibilityIcon,
417 UMA_ACCESSIBILITY), 350 UMA_ACCESSIBILITY),
418 default_(NULL), 351 default_(NULL),
419 detailed_popup_(NULL),
420 detailed_menu_(NULL), 352 detailed_menu_(NULL),
421 request_popup_view_state_(A11Y_NONE),
422 tray_icon_visible_(false), 353 tray_icon_visible_(false),
423 login_(GetCurrentLoginStatus()), 354 login_(GetCurrentLoginStatus()),
424 previous_accessibility_state_(GetAccessibilityState()), 355 previous_accessibility_state_(GetAccessibilityState()),
425 show_a11y_menu_on_lock_screen_(true) { 356 show_a11y_menu_on_lock_screen_(true) {
426 DCHECK(system_tray); 357 DCHECK(system_tray);
427 Shell::Get()->system_tray_notifier()->AddAccessibilityObserver(this); 358 Shell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
428 } 359 }
429 360
430 TrayAccessibility::~TrayAccessibility() { 361 TrayAccessibility::~TrayAccessibility() {
431 Shell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this); 362 Shell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this);
(...skipping 30 matching lines...) Expand all
462 (status != LoginStatus::LOCKED || !show_a11y_menu_on_lock_screen_)) 393 (status != LoginStatus::LOCKED || !show_a11y_menu_on_lock_screen_))
463 return NULL; 394 return NULL;
464 395
465 CHECK(default_ == NULL); 396 CHECK(default_ == NULL);
466 default_ = new tray::DefaultAccessibilityView(this); 397 default_ = new tray::DefaultAccessibilityView(this);
467 398
468 return default_; 399 return default_;
469 } 400 }
470 401
471 views::View* TrayAccessibility::CreateDetailedView(LoginStatus status) { 402 views::View* TrayAccessibility::CreateDetailedView(LoginStatus status) {
472 CHECK(detailed_popup_ == NULL);
473 CHECK(detailed_menu_ == NULL); 403 CHECK(detailed_menu_ == NULL);
474 404
475 if (request_popup_view_state_) { 405 ShellPort::Get()->RecordUserMetricsAction(
476 detailed_popup_ = 406 ash::UMA_STATUS_AREA_DETAILED_ACCESSIBILITY);
477 new tray::AccessibilityPopupView(request_popup_view_state_); 407 detailed_menu_ = CreateDetailedMenu();
478 detailed_popup_->Init(); 408 return detailed_menu_;
479 request_popup_view_state_ = A11Y_NONE;
480 return detailed_popup_;
481 } else {
482 ShellPort::Get()->RecordUserMetricsAction(
483 ash::UMA_STATUS_AREA_DETAILED_ACCESSABILITY);
484 detailed_menu_ = CreateDetailedMenu();
485 return detailed_menu_;
486 }
487 } 409 }
488 410
489 void TrayAccessibility::DestroyDefaultView() { 411 void TrayAccessibility::DestroyDefaultView() {
490 default_ = NULL; 412 default_ = NULL;
491 } 413 }
492 414
493 void TrayAccessibility::DestroyDetailedView() { 415 void TrayAccessibility::DestroyDetailedView() {
494 detailed_popup_ = NULL;
495 detailed_menu_ = NULL; 416 detailed_menu_ = NULL;
496 } 417 }
497 418
498 void TrayAccessibility::UpdateAfterLoginStatusChange(LoginStatus status) { 419 void TrayAccessibility::UpdateAfterLoginStatusChange(LoginStatus status) {
499 // Stores the a11y feature status on just entering the lock screen. 420 // Stores the a11y feature status on just entering the lock screen.
500 if (login_ != LoginStatus::LOCKED && status == LoginStatus::LOCKED) 421 if (login_ != LoginStatus::LOCKED && status == LoginStatus::LOCKED)
501 show_a11y_menu_on_lock_screen_ = (GetAccessibilityState() != A11Y_NONE); 422 show_a11y_menu_on_lock_screen_ = (GetAccessibilityState() != A11Y_NONE);
502 423
503 login_ = status; 424 login_ = status;
504 SetTrayIconVisible(GetInitialVisibility()); 425 SetTrayIconVisible(GetInitialVisibility());
505 } 426 }
506 427
507 void TrayAccessibility::OnAccessibilityModeChanged( 428 void TrayAccessibility::OnAccessibilityModeChanged(
508 AccessibilityNotificationVisibility notify) { 429 AccessibilityNotificationVisibility notify) {
509 SetTrayIconVisible(GetInitialVisibility()); 430 SetTrayIconVisible(GetInitialVisibility());
510 431
511 uint32_t accessibility_state = GetAccessibilityState(); 432 uint32_t accessibility_state = GetAccessibilityState();
512 // We'll get an extra notification if a braille display is connected when 433 // We'll get an extra notification if a braille display is connected when
513 // spoken feedback wasn't already enabled. This is because the braille 434 // spoken feedback wasn't already enabled. This is because the braille
514 // connection state is already updated when spoken feedback is enabled so 435 // connection state is already updated when spoken feedback is enabled so
515 // that the notifications can be consolidated into one. Therefore, we 436 // that the notifications can be consolidated into one. Therefore, we
516 // return early if there's no change in the state that we keep track of. 437 // return early if there's no change in the state that we keep track of.
517 if (accessibility_state == previous_accessibility_state_) 438 if (accessibility_state == previous_accessibility_state_)
518 return; 439 return;
440
441 if (detailed_menu_)
442 detailed_menu_->GetWidget()->Close();
443
444 message_center::MessageCenter::Get()->RemoveNotification(kNotificationId,
445 false /* by_user */);
446
519 // Contains bits for spoken feedback and braille display connected currently 447 // Contains bits for spoken feedback and braille display connected currently
520 // being enabled. 448 // being enabled.
521 uint32_t being_enabled = 449 uint32_t being_enabled =
522 (accessibility_state & ~previous_accessibility_state_) & 450 (accessibility_state & ~previous_accessibility_state_) &
523 (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED); 451 (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED);
524 if ((notify == A11Y_NOTIFICATION_SHOW) && being_enabled != A11Y_NONE) { 452 // Shows notification if |notify| is true and the spoken feedback is being
525 // Shows popup if |notify| is true and the spoken feedback is being enabled. 453 // enabled or if a braille is connected
James Cook 2017/05/16 00:56:18 super nit: "a braille display" and end with .
yiyix 2017/05/19 02:29:55 Done.
526 request_popup_view_state_ = being_enabled; 454 if (notify == A11Y_NOTIFICATION_SHOW && being_enabled &&
527 ShowDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); 455 being_enabled != A11Y_NONE) {
456 message_center::MessageCenter* message_center =
James Cook 2017/05/16 00:56:18 nit: move above line 444 and use |message_center|
yiyix 2017/05/19 02:29:56 Done.
457 message_center::MessageCenter::Get();
458 if (!message_center)
James Cook 2017/05/16 00:56:18 Does this happen in practice? In tests? You should
yiyix 2017/05/19 02:29:56 I was copying this dcheck from some test cases. I
459 return;
460
461 std::unique_ptr<message_center::Notification> notification;
462
463 base::string16 text;
464 base::string16 title;
465 if (being_enabled & A11Y_BRAILLE_DISPLAY_CONNECTED &&
466 being_enabled & A11Y_SPOKEN_FEEDBACK) {
467 text.append(l10n_util::GetStringUTF16(
James Cook 2017/05/16 00:56:18 just =, not append, here and below
yiyix 2017/05/19 02:29:55 Done.
468 IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED));
469 title.append(l10n_util::GetStringUTF16(
470 IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_BRAILLE_ENABLED_TITLE));
471 } else {
472 if (being_enabled & A11Y_BRAILLE_DISPLAY_CONNECTED) {
James Cook 2017/05/16 00:56:19 combine with else above to make else-if
yiyix 2017/05/19 02:29:56 Done.
473 text.append(l10n_util::GetStringUTF16(
474 IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED));
475 } else {
476 title.append(l10n_util::GetStringUTF16(
477 IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TITLE));
478 text.append(l10n_util::GetStringUTF16(
479 IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED));
480 }
481 }
482
483 notification = base::MakeUnique<message_center::Notification>(
James Cook 2017/05/16 00:56:18 move declaration here from 461
yiyix 2017/05/19 02:29:56 Done. I always forget that I suppose to declare it
484 message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, title, text,
485 gfx::Image(gfx::CreateVectorIcon(GetNotificationIcon(being_enabled),
486 ash::kMenuIconSize,
James Cook 2017/05/16 00:56:18 nit: no ash::
yiyix 2017/05/19 02:29:55 Done.
487 ash::kMenuIconColor)),
488 base::string16(), GURL(),
489 message_center::NotifierId(message_center::NotifierId::APPLICATION,
490 system_notifier::kNotifierAccessibility),
491 message_center::RichNotificationData(), nullptr);
492 message_center->AddNotification(std::move(notification));
James Cook 2017/05/16 00:56:19 or you could create the notification here with Mak
yiyix 2017/05/19 02:29:56 Done. I also realize that i removed the notificati
493
528 } else { 494 } else {
529 if (detailed_popup_) 495 message_center::MessageCenter::Get()->RemoveNotification(
530 detailed_popup_->GetWidget()->Close(); 496 kNotificationId, false /* by_user */);
531 if (detailed_menu_)
532 detailed_menu_->GetWidget()->Close();
533 } 497 }
534 498
535 previous_accessibility_state_ = accessibility_state; 499 previous_accessibility_state_ = accessibility_state;
536 } 500 }
537 501
538 } // namespace ash 502 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698