OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "chrome/browser/ui/views/subtle_notification_view.h" | 5 #include "chrome/browser/ui/views/subtle_notification_view.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
10 #include "base/strings/string_util.h" | |
10 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
11 #include "third_party/skia/include/core/SkColor.h" | 12 #include "third_party/skia/include/core/SkColor.h" |
13 #include "ui/accessibility/ax_view_state.h" | |
12 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
13 #include "ui/gfx/font_list.h" | 15 #include "ui/gfx/font_list.h" |
14 #include "ui/views/bubble/bubble_border.h" | 16 #include "ui/views/bubble/bubble_border.h" |
15 #include "ui/views/controls/label.h" | 17 #include "ui/views/controls/label.h" |
16 #include "ui/views/controls/link.h" | 18 #include "ui/views/controls/link.h" |
17 #include "ui/views/layout/box_layout.h" | 19 #include "ui/views/layout/box_layout.h" |
18 #include "ui/views/widget/widget.h" | 20 #include "ui/views/widget/widget.h" |
21 #include "ui/views/widget/widget_observer.h" | |
19 | 22 |
20 namespace { | 23 namespace { |
21 | 24 |
22 // Space between the site info label and the link. | 25 // Space between the site info label and the link. |
23 const int kMiddlePaddingPx = 30; | 26 const int kMiddlePaddingPx = 30; |
24 | 27 |
25 const int kOuterPaddingHorizPx = 40; | 28 const int kOuterPaddingHorizPx = 40; |
26 const int kOuterPaddingVertPx = 8; | 29 const int kOuterPaddingVertPx = 8; |
27 | 30 |
28 // Partially-transparent background color. | 31 // Partially-transparent background color. |
29 const SkColor kBackgroundColor = SkColorSetARGB(0xcc, 0x28, 0x2c, 0x32); | 32 const SkColor kBackgroundColor = SkColorSetARGB(0xcc, 0x28, 0x2c, 0x32); |
30 | 33 |
31 // Spacing around the key name. | 34 // Spacing around the key name. |
32 const int kKeyNameMarginHorizPx = 7; | 35 const int kKeyNameMarginHorizPx = 7; |
33 const int kKeyNameBorderPx = 1; | 36 const int kKeyNameBorderPx = 1; |
34 const int kKeyNameCornerRadius = 2; | 37 const int kKeyNameCornerRadius = 2; |
35 const int kKeyNamePaddingPx = 5; | 38 const int kKeyNamePaddingPx = 5; |
36 | 39 |
40 // Delimiter indicating there should be a segment displayed as a keyboard key. | |
41 const base::char16 kKeyNameDelimiter[] = {'|', '\0'}; | |
42 | |
37 } // namespace | 43 } // namespace |
38 | 44 |
39 // Class containing the instruction text. Contains fancy styling on the keyboard | 45 // Class containing the instruction text. Contains fancy styling on the keyboard |
40 // key (not just a simple label). | 46 // key (not just a simple label). |
41 class SubtleNotificationView::InstructionView : public views::View { | 47 class SubtleNotificationView::InstructionView : public views::View { |
42 public: | 48 public: |
43 // Creates an InstructionView with specific text. |text| may contain one or | 49 // Creates an InstructionView with specific text. |text| may contain one or |
44 // more segments delimited by a pair of pipes ('|'); each of these segments | 50 // more segments delimited by a pair of pipes ('|'); each of these segments |
45 // will be displayed as a keyboard key. e.g., "Press |Alt|+|Q| to exit" will | 51 // will be displayed as a keyboard key. e.g., "Press |Alt|+|Q| to exit" will |
46 // have "Alt" and "Q" rendered as keys. | 52 // have "Alt" and "Q" rendered as keys. |
47 InstructionView(const base::string16& text, | 53 InstructionView(const base::string16& text, |
48 const gfx::FontList& font_list, | 54 const gfx::FontList& font_list, |
49 SkColor foreground_color, | 55 SkColor foreground_color, |
50 SkColor background_color); | 56 SkColor background_color); |
51 | 57 |
58 base::string16 text() const { return text_; } | |
52 void SetText(const base::string16& text); | 59 void SetText(const base::string16& text); |
53 | 60 |
54 private: | 61 private: |
55 // Adds a label to the end of the notification text. If |format_as_key|, | 62 // Adds a label to the end of the notification text. If |format_as_key|, |
56 // surrounds the label in a rounded-rect border to indicate that it is a | 63 // surrounds the label in a rounded-rect border to indicate that it is a |
57 // keyboard key. | 64 // keyboard key. |
58 void AddTextSegment(const base::string16& text, bool format_as_key); | 65 void AddTextSegment(const base::string16& text, bool format_as_key); |
59 | 66 |
60 const gfx::FontList& font_list_; | 67 const gfx::FontList& font_list_; |
61 SkColor foreground_color_; | 68 SkColor foreground_color_; |
(...skipping 22 matching lines...) Expand all Loading... | |
84 | 91 |
85 void SubtleNotificationView::InstructionView::SetText( | 92 void SubtleNotificationView::InstructionView::SetText( |
86 const base::string16& text) { | 93 const base::string16& text) { |
87 // Avoid replacing the contents with the same text. | 94 // Avoid replacing the contents with the same text. |
88 if (text == text_) | 95 if (text == text_) |
89 return; | 96 return; |
90 | 97 |
91 RemoveAllChildViews(true); | 98 RemoveAllChildViews(true); |
92 | 99 |
93 // Parse |text|, looking for pipe-delimited segment. | 100 // Parse |text|, looking for pipe-delimited segment. |
94 std::vector<base::string16> segments = | 101 std::vector<base::string16> segments = base::SplitString( |
95 base::SplitString(text, base::ASCIIToUTF16("|"), base::TRIM_WHITESPACE, | 102 text, kKeyNameDelimiter, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
96 base::SPLIT_WANT_ALL); | |
97 // SplitString() returns empty strings for zero-length segments, so given an | 103 // SplitString() returns empty strings for zero-length segments, so given an |
98 // even number of pipes, there should always be an odd number of segments. | 104 // even number of pipes, there should always be an odd number of segments. |
99 // The exception is if |text| is entirely empty, in which case the returned | 105 // The exception is if |text| is entirely empty, in which case the returned |
100 // list is also empty (rather than containing a single empty string). | 106 // list is also empty (rather than containing a single empty string). |
101 DCHECK(segments.empty() || segments.size() % 2 == 1); | 107 DCHECK(segments.empty() || segments.size() % 2 == 1); |
102 | 108 |
103 // Add text segment, alternating between non-key (no border) and key (border) | 109 // Add text segment, alternating between non-key (no border) and key (border) |
104 // formatting. | 110 // formatting. |
105 bool format_as_key = false; | 111 bool format_as_key = false; |
106 for (const auto& segment : segments) { | 112 for (const auto& segment : segments) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 } | 180 } |
175 | 181 |
176 SubtleNotificationView::~SubtleNotificationView() {} | 182 SubtleNotificationView::~SubtleNotificationView() {} |
177 | 183 |
178 void SubtleNotificationView::UpdateContent( | 184 void SubtleNotificationView::UpdateContent( |
179 const base::string16& instruction_text, | 185 const base::string16& instruction_text, |
180 const base::string16& link_text) { | 186 const base::string16& link_text) { |
181 instruction_view_->SetText(instruction_text); | 187 instruction_view_->SetText(instruction_text); |
182 instruction_view_->SetVisible(!instruction_text.empty()); | 188 instruction_view_->SetVisible(!instruction_text.empty()); |
183 link_->SetText(link_text); | 189 link_->SetText(link_text); |
184 link_->SetVisible(!link_text.empty()); | 190 link_->SetVisible(!link_text.empty()); |
Matt Giuca
2016/07/14 01:16:02
I think you have to clear accessible_name_ here, o
Patti Lor
2016/07/19 01:31:51
:O Good catch thank you! I ended up changing the w
| |
191 | |
192 NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); | |
dmazzoni
2016/07/13 23:41:35
I think AX_EVENT_CHILDREN_CHANGED would be better
Patti Lor
2016/07/19 01:31:51
Done, thanks. Would you say |link_| and |instructi
tapted
2016/07/19 02:46:53
Yeah - this may depend on how we solve http://crbu
| |
193 NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); | |
185 } | 194 } |
186 | 195 |
187 // static | 196 // static |
188 views::Widget* SubtleNotificationView::CreatePopupWidget( | 197 views::Widget* SubtleNotificationView::CreatePopupWidget( |
189 gfx::NativeView parent_view, | 198 gfx::NativeView parent_view, |
190 SubtleNotificationView* view, | 199 SubtleNotificationView* view, |
191 bool accept_events) { | 200 bool accept_events) { |
192 // Initialize the popup. | 201 // Initialize the popup. |
193 views::Widget* popup = new views::Widget; | 202 views::Widget* popup = new views::Widget; |
194 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 203 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
195 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 204 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
196 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 205 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
197 params.parent = parent_view; | 206 params.parent = parent_view; |
198 params.accept_events = accept_events; | 207 params.accept_events = accept_events; |
199 popup->Init(params); | 208 popup->Init(params); |
200 popup->SetContentsView(view); | 209 popup->SetContentsView(view); |
201 // We set layout manager to nullptr to prevent the widget from sizing its | 210 // We set layout manager to nullptr to prevent the widget from sizing its |
202 // contents to the same size as itself. This prevents the widget contents from | 211 // contents to the same size as itself. This prevents the widget contents from |
203 // shrinking while we animate the height of the popup to give the impression | 212 // shrinking while we animate the height of the popup to give the impression |
204 // that it is sliding off the top of the screen. | 213 // that it is sliding off the top of the screen. |
205 // TODO(mgiuca): This probably isn't necessary now that there is no slide | 214 // TODO(mgiuca): This probably isn't necessary now that there is no slide |
206 // animation. Remove it. | 215 // animation. Remove it. |
207 popup->GetRootView()->SetLayoutManager(nullptr); | 216 popup->GetRootView()->SetLayoutManager(nullptr); |
208 | 217 |
218 // Allow accessibility events to be sent when the view is shown. | |
219 popup->AddObserver(view); | |
220 | |
209 return popup; | 221 return popup; |
210 } | 222 } |
223 | |
224 void SubtleNotificationView::SetAccessibleName( | |
225 const base::string16& accessible_name) { | |
226 base::RemoveChars(accessible_name, kKeyNameDelimiter, &accessible_name_); | |
227 } | |
228 | |
229 void SubtleNotificationView::GetAccessibleState(ui::AXViewState* state) { | |
230 state->role = ui::AX_ROLE_LABEL_TEXT; | |
231 | |
232 // If there is no accessible name set, use the displayed text, but ensure the | |
233 // '|' delimiters are removed. | |
dmazzoni
2016/07/13 23:41:35
What code removes the | delimiters?
Matt Giuca
2016/07/14 01:16:02
SetAccessibleName, just above, does this.
I agree
Patti Lor
2016/07/19 01:31:51
Have removed the side effect here, and left the co
| |
234 if (accessible_name_.empty()) | |
235 SetAccessibleName(instruction_view_->text()); | |
236 state->name = accessible_name_; | |
237 } | |
238 | |
239 void SubtleNotificationView::OnWidgetClosing(views::Widget* widget) { | |
240 if (widget && widget == GetWidget()) | |
241 widget->RemoveObserver(this); | |
242 } | |
243 | |
244 void SubtleNotificationView::OnWidgetVisibilityChanged(views::Widget* widget, | |
245 bool visible) { | |
246 if (visible) | |
247 NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); | |
248 } | |
OLD | NEW |