1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/views/toast_contents_view.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/compiler_specific.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/weak_ptr.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_delegate.h"
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/display.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/screen.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/message_center/message_center_style.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/notification.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/views/message_popup_collection.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/views/message_view.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/background.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/view.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/widget/widget.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/widget/widget_delegate.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(OS_WIN)
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using gfx::Screen;
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace message_center {
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The width of a toast before animated reveal and after closing.
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kClosedToastWidth = 5;
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// FadeIn/Out look a bit better if they are slightly longer then default slide.
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kFadeInOutDuration = 200;
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace.
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size ToastContentsView::GetToastSizeForView(const views::View* view) {
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int width = kNotificationWidth + view->GetInsets().width();
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return gfx::Size(width, view->GetHeightForWidth(width));
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ToastContentsView::ToastContentsView(
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& notification_id,
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::WeakPtr<MessagePopupCollection> collection)
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : collection_(collection),
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      id_(notification_id),
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      is_animating_bounds_(false),
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      is_closing_(false),
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      closing_animation_(NULL) {
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set_notify_enter_exit_on_child(true);
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Sets the transparent background. Then, when the message view is slid out,
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the whole toast seems to slide although the actual bound of the widget
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // remains. This is hacky but easier to keep the consistency.
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set_background(views::Background::CreateSolidBackground(0, 0, 0, 0));
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  fade_animation_.reset(new gfx::SlideAnimation(this));
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->SetSlideDuration(kFadeInOutDuration);
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CreateWidget(collection->parent());
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This is destroyed when the toast window closes.
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ToastContentsView::~ToastContentsView() {
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (collection_)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    collection_->ForgetToast(this);
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ToastContentsView::SetContents(MessageView* view,
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                    bool a11y_feedback_for_updates) {
78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool already_has_contents = child_count() > 0;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RemoveAllChildViews(true);
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  AddChildView(view);
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  preferred_size_ = GetToastSizeForView(view);
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Layout();
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If it has the contents already, this invocation means an update of the
85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // popup toast, and the new contents should be read through a11y feature.
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // The notification type should be ALERT, otherwise the accessibility message
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // won't be read for this view which returns ROLE_WINDOW.
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (already_has_contents && a11y_feedback_for_updates)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false);
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void ToastContentsView::UpdateContents(const Notification& notification,
930de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                       bool a11y_feedback_for_updates) {
940de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK_GT(child_count(), 0);
950de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  MessageView* message_view = static_cast<MessageView*>(child_at(0));
960de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  message_view->UpdateWithNotification(notification);
970de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (a11y_feedback_for_updates)
980de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false);
990de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
1000de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::RevealWithAnimation(gfx::Point origin) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Place/move the toast widgets. Currently it stacks the widgets from the
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // right-bottom of the work area.
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(mukai): allow to specify the placement policy from outside of this
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // class. The policy should be specified from preference on Windows, or
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the launcher alignment on ChromeOS.
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  origin_ = gfx::Point(origin.x() - preferred_size_.width(),
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       origin.y() - preferred_size_.height());
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Rect stable_bounds(origin_, preferred_size_);
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetBoundsInstantly(GetClosedToastBounds(stable_bounds));
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartFadeIn();
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetBoundsWithAnimation(stable_bounds);
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ToastContentsView::CloseWithAnimation() {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (is_closing_)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  is_closing_ = true;
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartFadeOut();
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::SetBoundsInstantly(gfx::Rect new_bounds) {
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (new_bounds == bounds())
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  origin_ = new_bounds.origin();
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!GetWidget())
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetWidget()->SetBounds(new_bounds);
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::SetBoundsWithAnimation(gfx::Rect new_bounds) {
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (new_bounds == bounds())
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  origin_ = new_bounds.origin();
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!GetWidget())
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This picks up the current bounds, so if there was a previous animation
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // half-done, the next one will pick up from the current location.
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This is the only place that should query current location of the Widget
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // on screen, the rest should refer to the bounds_.
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  animated_bounds_start_ = GetWidget()->GetWindowBoundsInScreen();
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  animated_bounds_end_ = new_bounds;
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (collection_)
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    collection_->IncrementDeferCounter();
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (bounds_animation_.get())
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bounds_animation_->Stop();
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bounds_animation_.reset(new gfx::SlideAnimation(this));
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bounds_animation_->Show();
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::StartFadeIn() {
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The decrement is done in OnBoundsAnimationEndedOrCancelled callback.
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (collection_)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    collection_->IncrementDeferCounter();
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->Stop();
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetWidget()->SetOpacity(0);
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetWidget()->ShowInactive();
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->Reset(0);
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->Show();
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ToastContentsView::StartFadeOut() {
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The decrement is done in OnBoundsAnimationEndedOrCancelled callback.
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (collection_)
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    collection_->IncrementDeferCounter();
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->Stop();
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  closing_animation_ = (is_closing_ ? fade_animation_.get() : NULL);
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->Reset(1);
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fade_animation_->Hide();
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::OnBoundsAnimationEndedOrCancelled(
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const gfx::Animation* animation) {
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (is_closing_ && closing_animation_ == animation && GetWidget()) {
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    views::Widget* widget = GetWidget();
1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // TODO(dewittj): This is a workaround to prevent a nasty bug where
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // closing a transparent widget doesn't actually remove the window,
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // causing entire areas of the screen to become unresponsive to clicks.
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // See crbug.com/243469
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    widget->Hide();
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#if defined(OS_WIN)
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    widget->SetOpacity(0xFF);
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    widget->Close();
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // This cannot be called before GetWidget()->Close(). Decrementing defer count
200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // will invoke update, which may invoke another close animation with
201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // incrementing defer counter. Close() after such process will cause a
202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // mismatch between increment/decrement. See crbug.com/238477
203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (collection_)
204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    collection_->DecrementDeferCounter();
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// gfx::AnimationDelegate
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ToastContentsView::AnimationProgressed(const gfx::Animation* animation) {
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (animation == bounds_animation_.get()) {
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::Rect current(animation->CurrentValueBetween(
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        animated_bounds_start_, animated_bounds_end_));
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GetWidget()->SetBounds(current);
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (animation == fade_animation_.get()) {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    unsigned char opacity =
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        static_cast<unsigned char>(fade_animation_->GetCurrentValue() * 255);
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GetWidget()->SetOpacity(opacity);
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ToastContentsView::AnimationEnded(const gfx::Animation* animation) {
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OnBoundsAnimationEndedOrCancelled(animation);
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::AnimationCanceled(
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const gfx::Animation* animation) {
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OnBoundsAnimationEndedOrCancelled(animation);
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// views::WidgetDelegate
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::View* ToastContentsView::GetContentsView() {
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return this;
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::WindowClosing() {
235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!is_closing_ && collection_.get())
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    collection_->ForgetToast(this);
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ToastContentsView::OnDisplayChanged() {
240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  views::Widget* widget = GetWidget();
241a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!widget)
242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
243a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  gfx::NativeView native_view = widget->GetNativeView();
245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!native_view || !collection_.get())
246a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
247a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  collection_->OnDisplayMetricsChanged(
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      Screen::GetScreenFor(native_view)->GetDisplayNearestWindow(native_view));
250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ToastContentsView::OnWorkAreaChanged() {
253a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  views::Widget* widget = GetWidget();
254a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!widget)
255a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
256a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  gfx::NativeView native_view = widget->GetNativeView();
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!native_view || !collection_.get())
259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
260a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  collection_->OnDisplayMetricsChanged(
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      Screen::GetScreenFor(native_view)->GetDisplayNearestWindow(native_view));
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// views::View
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::OnMouseEntered(const ui::MouseEvent& event) {
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (collection_)
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    collection_->OnMouseEntered(this);
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::OnMouseExited(const ui::MouseEvent& event) {
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (collection_)
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    collection_->OnMouseExited(this);
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ToastContentsView::Layout() {
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (child_count() > 0) {
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    child_at(0)->SetBounds(
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        0, 0, preferred_size_.width(), preferred_size_.height());
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size ToastContentsView::GetPreferredSize() const {
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return child_count() ? GetToastSizeForView(child_at(0)) : gfx::Size();
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ToastContentsView::GetAccessibleState(ui::AXViewState* state) {
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (child_count() > 0)
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    child_at(0)->GetAccessibleState(state);
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_WINDOW;
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ToastContentsView::ClickOnNotification(
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& notification_id) {
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (collection_)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    collection_->ClickOnNotification(notification_id);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ToastContentsView::RemoveNotification(
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& notification_id,
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool by_user) {
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (collection_)
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    collection_->RemoveNotification(notification_id, by_user);
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<ui::MenuModel> ToastContentsView::CreateMenuModel(
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const NotifierId& notifier_id,
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::string16& display_source) {
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Should not reach, the context menu should be handled in
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // MessagePopupCollection.
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return scoped_ptr<ui::MenuModel>();
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ToastContentsView::HasClickedListener(
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& notification_id) {
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!collection_)
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return collection_->HasClickedListener(notification_id);
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ToastContentsView::ClickOnNotificationButton(
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& notification_id,
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int button_index) {
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (collection_)
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    collection_->ClickOnNotificationButton(notification_id, button_index);
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ToastContentsView::CreateWidget(gfx::NativeView parent) {
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  params.keep_on_top = true;
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (parent)
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    params.parent = parent;
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  params.delegate = this;
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  views::Widget* widget = new views::Widget();
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  widget->set_focus_on_creation(false);
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(OS_WIN)
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // We want to ensure that this toast always goes to the native desktop,
341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // not the Ash desktop (since there is already another toast contents view
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // there.
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!params.parent)
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    params.native_widget = new views::DesktopNativeWidgetAura(widget);
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  widget->Init(params);
348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Rect ToastContentsView::GetClosedToastBounds(gfx::Rect bounds) {
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return gfx::Rect(bounds.x() + bounds.width() - kClosedToastWidth,
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   bounds.y(),
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   kClosedToastWidth,
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   bounds.height());
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace message_center
358