gpu: Tweak Android WebGL test expectations
[chromium-blink-merge.git] / ui / message_center / views / toast_contents_view.cc
blobb7dae986a20d9bc8adc2c99c6fd6fb3557d3c25d
1 // Copyright (c) 2013 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.
5 #include "ui/message_center/views/toast_contents_view.h"
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/time/time.h"
12 #include "base/timer/timer.h"
13 #include "ui/base/accessibility/accessible_view_state.h"
14 #include "ui/base/animation/animation_delegate.h"
15 #include "ui/base/animation/slide_animation.h"
16 #include "ui/gfx/display.h"
17 #include "ui/gfx/screen.h"
18 #include "ui/message_center/message_center.h"
19 #include "ui/message_center/message_center_style.h"
20 #include "ui/message_center/notification.h"
21 #include "ui/message_center/views/message_popup_collection.h"
22 #include "ui/message_center/views/message_view.h"
23 #include "ui/views/view.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/views/widget/widget_delegate.h"
27 namespace message_center {
28 namespace {
30 // The width of a toast before animated reveal and after closing.
31 const int kClosedToastWidth = 5;
33 // FadeIn/Out look a bit better if they are slightly longer then default slide.
34 const int kFadeInOutDuration = 200;
36 } // namespace.
38 // static
39 gfx::Size ToastContentsView::GetToastSizeForView(views::View* view) {
40 int width = kNotificationWidth + view->GetInsets().width();
41 return gfx::Size(width, view->GetHeightForWidth(width));
44 ToastContentsView::ToastContentsView(
45 const Notification* notification,
46 base::WeakPtr<MessagePopupCollection> collection,
47 MessageCenter* message_center)
48 : collection_(collection),
49 message_center_(message_center),
50 id_(notification->id()),
51 is_animating_bounds_(false),
52 is_closing_(false),
53 closing_animation_(NULL) {
54 DCHECK(collection_);
56 set_notify_enter_exit_on_child(true);
57 // Sets the transparent background. Then, when the message view is slid out,
58 // the whole toast seems to slide although the actual bound of the widget
59 // remains. This is hacky but easier to keep the consistency.
60 set_background(views::Background::CreateSolidBackground(0, 0, 0, 0));
62 fade_animation_.reset(new ui::SlideAnimation(this));
63 fade_animation_->SetSlideDuration(kFadeInOutDuration);
66 // This is destroyed when the toast window closes.
67 ToastContentsView::~ToastContentsView() {
70 views::Widget* ToastContentsView::CreateWidget(gfx::NativeView parent) {
71 views::Widget::InitParams params(
72 views::Widget::InitParams::TYPE_POPUP);
73 params.keep_on_top = true;
74 if (parent)
75 params.parent = parent;
76 else
77 params.top_level = true;
78 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
79 params.delegate = this;
80 views::Widget* widget = new views::Widget();
81 widget->set_focus_on_creation(false);
82 widget->Init(params);
83 return widget;
86 void ToastContentsView::SetContents(MessageView* view) {
87 bool already_has_contents = child_count() > 0;
88 RemoveAllChildViews(true);
89 AddChildView(view);
90 preferred_size_ = GetToastSizeForView(view);
91 Layout();
92 // If it has the contents already, this invocation means an update of the
93 // popup toast, and the new contents should be read through a11y feature.
94 if (already_has_contents)
95 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, false);
98 void ToastContentsView::RevealWithAnimation(gfx::Point origin) {
99 // Place/move the toast widgets. Currently it stacks the widgets from the
100 // right-bottom of the work area.
101 // TODO(mukai): allow to specify the placement policy from outside of this
102 // class. The policy should be specified from preference on Windows, or
103 // the launcher alignment on ChromeOS.
104 origin_ = gfx::Point(origin.x() - preferred_size_.width(),
105 origin.y() - preferred_size_.height());
107 gfx::Rect stable_bounds(origin_, preferred_size_);
109 SetBoundsInstantly(GetClosedToastBounds(stable_bounds));
110 StartFadeIn();
111 SetBoundsWithAnimation(stable_bounds);
114 void ToastContentsView::CloseWithAnimation(bool mark_as_shown) {
115 if (is_closing_)
116 return;
117 is_closing_ = true;
118 if (collection_)
119 collection_->RemoveToast(this);
120 if (mark_as_shown)
121 message_center_->MarkSinglePopupAsShown(id(), false);
122 StartFadeOut();
125 void ToastContentsView::SetBoundsInstantly(gfx::Rect new_bounds) {
126 if (new_bounds == bounds())
127 return;
129 origin_ = new_bounds.origin();
130 if (!GetWidget())
131 return;
132 GetWidget()->SetBounds(new_bounds);
135 void ToastContentsView::SetBoundsWithAnimation(gfx::Rect new_bounds) {
136 if (new_bounds == bounds())
137 return;
139 origin_ = new_bounds.origin();
140 if (!GetWidget())
141 return;
143 // This picks up the current bounds, so if there was a previous animation
144 // half-done, the next one will pick up from the current location.
145 // This is the only place that should query current location of the Widget
146 // on screen, the rest should refer to the bounds_.
147 animated_bounds_start_ = GetWidget()->GetWindowBoundsInScreen();
148 animated_bounds_end_ = new_bounds;
150 if (collection_)
151 collection_->IncrementDeferCounter();
153 if (bounds_animation_.get())
154 bounds_animation_->Stop();
156 bounds_animation_.reset(new ui::SlideAnimation(this));
157 bounds_animation_->Show();
160 void ToastContentsView::StartFadeIn() {
161 // The decrement is done in OnBoundsAnimationEndedOrCancelled callback.
162 if (collection_)
163 collection_->IncrementDeferCounter();
164 fade_animation_->Stop();
166 GetWidget()->SetOpacity(0);
167 GetWidget()->Show();
168 fade_animation_->Reset(0);
169 fade_animation_->Show();
172 void ToastContentsView::StartFadeOut() {
173 // The decrement is done in OnBoundsAnimationEndedOrCancelled callback.
174 if (collection_)
175 collection_->IncrementDeferCounter();
176 fade_animation_->Stop();
178 closing_animation_ = (is_closing_ ? fade_animation_.get() : NULL);
179 fade_animation_->Reset(1);
180 fade_animation_->Hide();
183 void ToastContentsView::OnBoundsAnimationEndedOrCancelled(
184 const ui::Animation* animation) {
185 if (is_closing_ && closing_animation_ == animation && GetWidget()) {
186 views::Widget* widget = GetWidget();
187 #if defined(USE_AURA)
188 // TODO(dewittj): This is a workaround to prevent a nasty bug where
189 // closing a transparent widget doesn't actually remove the window,
190 // causing entire areas of the screen to become unresponsive to clicks.
191 // See crbug.com/243469
192 widget->Hide();
193 # if defined(OS_WIN)
194 widget->SetOpacity(0xFF);
195 # endif
196 #endif
197 widget->Close();
200 // This cannot be called before GetWidget()->Close(). Decrementing defer count
201 // will invoke update, which may invoke another close animation with
202 // incrementing defer counter. Close() after such process will cause a
203 // mismatch between increment/decrement. See crbug.com/238477
204 if (collection_)
205 collection_->DecrementDeferCounter();
208 // ui::AnimationDelegate
209 void ToastContentsView::AnimationProgressed(const ui::Animation* animation) {
210 if (animation == bounds_animation_.get()) {
211 gfx::Rect current(animation->CurrentValueBetween(
212 animated_bounds_start_, animated_bounds_end_));
213 GetWidget()->SetBounds(current);
214 } else if (animation == fade_animation_.get()) {
215 unsigned char opacity =
216 static_cast<unsigned char>(fade_animation_->GetCurrentValue() * 255);
217 GetWidget()->SetOpacity(opacity);
221 void ToastContentsView::AnimationEnded(const ui::Animation* animation) {
222 OnBoundsAnimationEndedOrCancelled(animation);
225 void ToastContentsView::AnimationCanceled(
226 const ui::Animation* animation) {
227 OnBoundsAnimationEndedOrCancelled(animation);
230 // views::WidgetDelegate
231 views::View* ToastContentsView::GetContentsView() {
232 return this;
235 void ToastContentsView::WindowClosing() {
236 if (!is_closing_ && collection_)
237 collection_->RemoveToast(this);
240 bool ToastContentsView::CanActivate() const {
241 #if defined(OS_WIN) && defined(USE_AURA)
242 return true;
243 #else
244 return false;
245 #endif
248 void ToastContentsView::OnDisplayChanged() {
249 views::Widget* widget = GetWidget();
250 if (!widget)
251 return;
253 gfx::NativeView native_view = widget->GetNativeView();
254 if (!native_view || !collection_)
255 return;
257 collection_->OnDisplayBoundsChanged(gfx::Screen::GetScreenFor(
258 native_view)->GetDisplayNearestWindow(native_view));
261 void ToastContentsView::OnWorkAreaChanged() {
262 views::Widget* widget = GetWidget();
263 if (!widget)
264 return;
266 gfx::NativeView native_view = widget->GetNativeView();
267 if (!native_view || !collection_)
268 return;
270 collection_->OnDisplayBoundsChanged(gfx::Screen::GetScreenFor(
271 native_view)->GetDisplayNearestWindow(native_view));
274 // views::View
275 void ToastContentsView::OnMouseEntered(const ui::MouseEvent& event) {
276 if (collection_)
277 collection_->OnMouseEntered(this);
280 void ToastContentsView::OnMouseExited(const ui::MouseEvent& event) {
281 if (collection_)
282 collection_->OnMouseExited(this);
285 void ToastContentsView::Layout() {
286 if (child_count() > 0) {
287 child_at(0)->SetBounds(
288 0, 0, preferred_size_.width(), preferred_size_.height());
292 gfx::Size ToastContentsView::GetPreferredSize() {
293 return child_count() ? GetToastSizeForView(child_at(0)) : gfx::Size();
296 void ToastContentsView::GetAccessibleState(ui::AccessibleViewState* state) {
297 if (child_count() > 0)
298 child_at(0)->GetAccessibleState(state);
299 state->role = ui::AccessibilityTypes::ROLE_WINDOW;
302 gfx::Rect ToastContentsView::GetClosedToastBounds(gfx::Rect bounds) {
303 return gfx::Rect(bounds.x() + bounds.width() - kClosedToastWidth,
304 bounds.y(),
305 kClosedToastWidth,
306 bounds.height());
309 } // namespace message_center