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

Side by Side Diff: ash/common/system/toast/toast_overlay.cc

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 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
« no previous file with comments | « ash/common/system/toast/toast_overlay.h ('k') | ash/common/system/tray/actionable_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "ash/common/system/toast/toast_overlay.h"
6
7 #include "ash/common/shelf/wm_shelf.h"
8 #include "ash/common/wm_shell.h"
9 #include "ash/common/wm_window.h"
10 #include "ash/public/cpp/shell_window_ids.h"
11 #include "ash/root_window_controller.h"
12 #include "ash/strings/grit/ash_strings.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "third_party/skia/include/core/SkColor.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/font_list.h"
21 #include "ui/views/border.h"
22 #include "ui/views/controls/button/label_button.h"
23 #include "ui/views/controls/label.h"
24 #include "ui/views/layout/box_layout.h"
25 #include "ui/views/view.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/views/widget/widget_delegate.h"
28 #include "ui/wm/core/window_animations.h"
29
30 namespace ash {
31
32 namespace {
33
34 // Offset of the overlay from the edge of the work area.
35 const int kOffset = 5;
36
37 // Font style used for modifier key labels.
38 const ui::ResourceBundle::FontStyle kTextFontStyle =
39 ui::ResourceBundle::MediumFont;
40
41 // Duration of slide animation when overlay is shown or hidden.
42 const int kSlideAnimationDurationMs = 100;
43
44 // Colors for the dismiss button.
45 const SkColor kButtonBackgroundColor = SkColorSetARGB(0xFF, 0x32, 0x32, 0x32);
46 const SkColor kButtonTextColor = SkColorSetARGB(0xFF, 0x7B, 0xAA, 0xF7);
47
48 // These values are in DIP.
49 const int kToastHorizontalSpacing = 16;
50 const int kToastVerticalSpacing = 16;
51 const int kToastMaximumWidth = 568;
52 const int kToastMinimumWidth = 288;
53
54 // Returns the work area bounds for the root window where new windows are added
55 // (including new toasts).
56 gfx::Rect GetUserWorkAreaBounds() {
57 return WmShelf::ForWindow(WmShell::Get()->GetRootWindowForNewWindows())
58 ->GetUserWorkAreaBounds();
59 }
60
61 } // anonymous namespace
62
63 ///////////////////////////////////////////////////////////////////////////////
64 // ToastOverlayLabel
65 class ToastOverlayLabel : public views::Label {
66 public:
67 explicit ToastOverlayLabel(const base::string16& label);
68 ~ToastOverlayLabel() override;
69
70 private:
71 DISALLOW_COPY_AND_ASSIGN(ToastOverlayLabel);
72 };
73
74 ToastOverlayLabel::ToastOverlayLabel(const base::string16& label) {
75 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
76
77 SetText(label);
78 SetHorizontalAlignment(gfx::ALIGN_LEFT);
79 SetFontList(rb->GetFontList(kTextFontStyle));
80 SetAutoColorReadabilityEnabled(false);
81 SetMultiLine(true);
82 SetEnabledColor(SK_ColorWHITE);
83 SetDisabledColor(SK_ColorWHITE);
84 SetSubpixelRenderingEnabled(false);
85
86 int verticalSpacing =
87 kToastVerticalSpacing - (GetPreferredSize().height() - GetBaseline());
88 SetBorder(views::CreateEmptyBorder(verticalSpacing, kToastHorizontalSpacing,
89 verticalSpacing, kToastHorizontalSpacing));
90 }
91
92 ToastOverlayLabel::~ToastOverlayLabel() {}
93
94 ///////////////////////////////////////////////////////////////////////////////
95 // ToastOverlayButton
96 class ToastOverlayButton : public views::LabelButton {
97 public:
98 explicit ToastOverlayButton(views::ButtonListener* listener,
99 const base::string16& label);
100 ~ToastOverlayButton() override {}
101
102 private:
103 friend class ToastOverlay; // for ToastOverlay::ClickDismissButtonForTesting.
104
105 DISALLOW_COPY_AND_ASSIGN(ToastOverlayButton);
106 };
107
108 ToastOverlayButton::ToastOverlayButton(views::ButtonListener* listener,
109 const base::string16& text)
110 : views::LabelButton(listener, text) {
111 SetInkDropMode(InkDropMode::ON);
112 set_has_ink_drop_action_on_click(true);
113 set_ink_drop_base_color(SK_ColorWHITE);
114
115 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
116
117 SetEnabledTextColors(kButtonTextColor);
118 SetFontList(rb->GetFontList(kTextFontStyle));
119
120 // Treat the space below the baseline as a margin.
121 int verticalSpacing = kToastVerticalSpacing -
122 (GetPreferredSize().height() - label()->GetBaseline());
123 SetBorder(views::CreateEmptyBorder(verticalSpacing, kToastHorizontalSpacing,
124 verticalSpacing, kToastHorizontalSpacing));
125 }
126
127 ///////////////////////////////////////////////////////////////////////////////
128 // ToastOverlayView
129 class ToastOverlayView : public views::View, public views::ButtonListener {
130 public:
131 // This object is not owned by the views hierarchy or by the widget.
132 ToastOverlayView(ToastOverlay* overlay,
133 const base::string16& text,
134 const base::Optional<base::string16>& dismiss_text);
135 ~ToastOverlayView() override;
136
137 // views::View overrides:
138 void OnPaint(gfx::Canvas* canvas) override;
139
140 ToastOverlayButton* button() { return button_; }
141
142 private:
143 // views::View overrides:
144 gfx::Size GetMaximumSize() const override;
145 gfx::Size GetMinimumSize() const override;
146
147 // views::ButtonListener overrides:
148 void ButtonPressed(views::Button* sender, const ui::Event& event) override;
149
150 ToastOverlay* overlay_ = nullptr; // weak
151 ToastOverlayButton* button_ = nullptr; // weak
152
153 DISALLOW_COPY_AND_ASSIGN(ToastOverlayView);
154 };
155
156 ToastOverlayView::ToastOverlayView(
157 ToastOverlay* overlay,
158 const base::string16& text,
159 const base::Optional<base::string16>& dismiss_text)
160 : overlay_(overlay) {
161 auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
162 SetLayoutManager(layout);
163
164 if (dismiss_text.has_value()) {
165 button_ = new ToastOverlayButton(
166 this, dismiss_text.value().empty()
167 ? l10n_util::GetStringUTF16(IDS_ASH_TOAST_DISMISS_BUTTON)
168 : dismiss_text.value());
169 }
170
171 ToastOverlayLabel* label = new ToastOverlayLabel(text);
172 AddChildView(label);
173 layout->SetFlexForView(label, 1);
174
175 if (button_) {
176 label->SetMaximumWidth(
177 GetMaximumSize().width() - button_->GetPreferredSize().width() -
178 kToastHorizontalSpacing * 2 - kToastHorizontalSpacing * 2);
179 AddChildView(button_);
180 }
181 }
182
183 ToastOverlayView::~ToastOverlayView() {}
184
185 void ToastOverlayView::OnPaint(gfx::Canvas* canvas) {
186 cc::PaintFlags flags;
187 flags.setStyle(cc::PaintFlags::kFill_Style);
188 flags.setColor(kButtonBackgroundColor);
189 canvas->DrawRoundRect(GetLocalBounds(), 2, flags);
190 views::View::OnPaint(canvas);
191 }
192
193 gfx::Size ToastOverlayView::GetMinimumSize() const {
194 return gfx::Size(kToastMinimumWidth, 0);
195 }
196
197 gfx::Size ToastOverlayView::GetMaximumSize() const {
198 gfx::Rect work_area_bounds = GetUserWorkAreaBounds();
199 return gfx::Size(kToastMaximumWidth, work_area_bounds.height() - kOffset * 2);
200 }
201
202 void ToastOverlayView::ButtonPressed(views::Button* sender,
203 const ui::Event& event) {
204 DCHECK_EQ(button_, sender);
205 overlay_->Show(false);
206 }
207
208 ///////////////////////////////////////////////////////////////////////////////
209 // ToastOverlay
210 ToastOverlay::ToastOverlay(Delegate* delegate,
211 const base::string16& text,
212 base::Optional<base::string16> dismiss_text)
213 : delegate_(delegate),
214 text_(text),
215 dismiss_text_(dismiss_text),
216 overlay_widget_(new views::Widget),
217 overlay_view_(new ToastOverlayView(this, text, dismiss_text)),
218 widget_size_(overlay_view_->GetPreferredSize()) {
219 views::Widget::InitParams params;
220 params.type = views::Widget::InitParams::TYPE_POPUP;
221 params.name = "ToastOverlay";
222 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
223 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
224 params.accept_events = true;
225 params.keep_on_top = true;
226 params.remove_standard_frame = true;
227 params.bounds = CalculateOverlayBounds();
228 // Show toasts above the app list and below the lock screen.
229 WmShell::Get()
230 ->GetRootWindowForNewWindows()
231 ->GetRootWindowController()
232 ->ConfigureWidgetInitParamsForContainer(
233 overlay_widget_.get(), kShellWindowId_SystemModalContainer, &params);
234 overlay_widget_->Init(params);
235 overlay_widget_->SetVisibilityChangedAnimationsEnabled(true);
236 overlay_widget_->SetContentsView(overlay_view_.get());
237 overlay_widget_->SetBounds(CalculateOverlayBounds());
238
239 WmWindow* overlay_window = WmWindow::Get(overlay_widget_->GetNativeWindow());
240 overlay_window->SetVisibilityAnimationType(
241 ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
242 overlay_window->SetVisibilityAnimationDuration(
243 base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs));
244 }
245
246 ToastOverlay::~ToastOverlay() {
247 overlay_widget_->Close();
248 }
249
250 void ToastOverlay::Show(bool visible) {
251 if (overlay_widget_->GetLayer()->GetTargetVisibility() == visible)
252 return;
253
254 ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
255 DCHECK(animator);
256 if (animator->is_animating()) {
257 // Showing during hiding animation doesn't happen since, ToastOverlay should
258 // be one-time-use and not be reused.
259 DCHECK(!visible);
260
261 return;
262 }
263
264 base::TimeDelta original_duration = animator->GetTransitionDuration();
265 ui::ScopedLayerAnimationSettings animation_settings(animator);
266 // ScopedLayerAnimationSettings ctor chanes the transition duration, so change
267 // back it to the original value (should be zero).
268 animation_settings.SetTransitionDuration(original_duration);
269
270 animation_settings.AddObserver(this);
271
272 if (visible) {
273 overlay_widget_->Show();
274
275 // Notify accessibility about the overlay.
276 overlay_view_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false);
277 } else {
278 overlay_widget_->Hide();
279 }
280 }
281
282 gfx::Rect ToastOverlay::CalculateOverlayBounds() {
283 gfx::Rect bounds = GetUserWorkAreaBounds();
284 int target_y = bounds.bottom() - widget_size_.height() - kOffset;
285 bounds.ClampToCenteredSize(widget_size_);
286 bounds.set_y(target_y);
287 return bounds;
288 }
289
290 void ToastOverlay::OnImplicitAnimationsScheduled() {}
291
292 void ToastOverlay::OnImplicitAnimationsCompleted() {
293 if (!overlay_widget_->GetLayer()->GetTargetVisibility())
294 delegate_->OnClosed();
295 }
296
297 views::Widget* ToastOverlay::widget_for_testing() {
298 return overlay_widget_.get();
299 }
300
301 ToastOverlayButton* ToastOverlay::dismiss_button_for_testing() {
302 return overlay_view_->button();
303 }
304
305 void ToastOverlay::ClickDismissButtonForTesting(const ui::Event& event) {
306 DCHECK(overlay_view_->button());
307 overlay_view_->button()->NotifyClick(event);
308 }
309
310 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/system/toast/toast_overlay.h ('k') | ash/common/system/tray/actionable_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698