* Make web/system trays delegates instead of bubbles.
* Move TrayBubbleWrapper to trays.
* Remove remaining ash dependencies in message_center views.

Code diagram with changes:
https://docs.google.com/drawings/d/1B6ZxXObmrDFzgWEHmkP_Ppt2BFbOL9kXzakOmY0sXe0/edit

BUG=150872
For ash/wm/gestures/tray_gesture_handler.cc:
[email protected]

Review URL: https://chromiumcodereview.appspot.com/11154022

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162849 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ash/system/web_notification/message_center_bubble.cc b/ash/system/web_notification/message_center_bubble.cc
index f2dd9ed..316ea6d 100644
--- a/ash/system/web_notification/message_center_bubble.cc
+++ b/ash/system/web_notification/message_center_bubble.cc
@@ -4,46 +4,43 @@
 
 #include "ash/system/web_notification/message_center_bubble.h"
 
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/tray/tray_views.h"
-#include "ash/system/web_notification/web_notification_list.h"
-#include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/system/web_notification/web_notification_view.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/size.h"
+#include "ui/views/controls/button/text_button.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/painter.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
-namespace ash {
-
-using internal::TrayPopupTextButton;
-
 namespace message_center {
 
-// Web Notification Bubble constants
+namespace {
+
 const int kWebNotificationBubbleMinHeight = 80;
 const int kWebNotificationBubbleMaxHeight = 400;
+const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa);
 
 // The view for the buttons at the bottom of the web notification tray.
 class WebNotificationButtonView : public views::View,
                                   public views::ButtonListener {
  public:
-  explicit WebNotificationButtonView(WebNotificationTray* tray)
-  : tray_(tray),
-    close_all_button_(NULL) {
+  explicit WebNotificationButtonView(
+      WebNotificationList::Delegate* list_delegate)
+      : list_delegate_(list_delegate),
+        close_all_button_(NULL) {
     set_background(views::Background::CreateBackgroundPainter(
         true,
         views::Painter::CreateVerticalGradient(
-            kHeaderBackgroundColorLight,
-            kHeaderBackgroundColorDark)));
+            WebNotificationBubble::kHeaderBackgroundColorLight,
+            WebNotificationBubble::kHeaderBackgroundColorDark)));
     set_border(views::Border::CreateSolidSidedBorder(
-        2, 0, 0, 0, ash::kBorderDarkColor));
+        2, 0, 0, 0, kBorderDarkColor));
 
     views::GridLayout* layout = new views::GridLayout(this);
     SetLayoutManager(layout);
@@ -52,11 +49,16 @@
     columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
                        0, /* resize percent */
                        views::GridLayout::USE_PREF, 0, 0);
+    columns->AddPaddingColumn(0, 4);
 
     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-    close_all_button_ = new TrayPopupTextButton(
+    close_all_button_ = new views::TextButton(
         this, rb.GetLocalizedString(IDS_ASH_WEB_NOTFICATION_TRAY_CLEAR_ALL));
+    close_all_button_->set_alignment(views::TextButton::ALIGN_CENTER);
+    close_all_button_->set_focusable(true);
+    close_all_button_->set_request_focus_on_press(false);
 
+    layout->AddPaddingRow(0, 4);
     layout->StartRow(0, 0);
     layout->AddView(close_all_button_);
   }
@@ -71,75 +73,137 @@
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE {
     if (sender == close_all_button_)
-      tray_->SendRemoveAllNotifications();
+      list_delegate_->SendRemoveAllNotifications();
   }
 
  private:
-  WebNotificationTray* tray_;
-  internal::TrayPopupTextButton* close_all_button_;
+  WebNotificationList::Delegate* list_delegate_;
+  views::TextButton* close_all_button_;
 
   DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView);
 };
 
+// A custom scroll-view that has a specified size.
+class FixedSizedScrollView : public views::ScrollView {
+ public:
+  FixedSizedScrollView() {
+    set_focusable(true);
+    set_notify_enter_exit_on_child(true);
+  }
+
+  virtual ~FixedSizedScrollView() {}
+
+  void SetFixedSize(const gfx::Size& size) {
+    if (fixed_size_ == size)
+      return;
+    fixed_size_ = size;
+    PreferredSizeChanged();
+  }
+
+  // views::View overrides.
+  virtual gfx::Size GetPreferredSize() OVERRIDE {
+    gfx::Size size = fixed_size_.IsEmpty() ?
+        GetContents()->GetPreferredSize() : fixed_size_;
+    gfx::Insets insets = GetInsets();
+    size.Enlarge(insets.width(), insets.height());
+    return size;
+  }
+
+  virtual void Layout() OVERRIDE {
+    views::View* contents = GetContents();
+    gfx::Rect bounds = gfx::Rect(contents->GetPreferredSize());
+    bounds.set_width(std::max(0, width() - GetScrollBarWidth()));
+    contents->SetBoundsRect(bounds);
+
+    views::ScrollView::Layout();
+    if (!vertical_scroll_bar()->visible()) {
+      gfx::Rect bounds = contents->bounds();
+      bounds.set_width(bounds.width() + GetScrollBarWidth());
+      contents->SetBoundsRect(bounds);
+    }
+  }
+
+  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE {
+    views::View* contents = GetContents();
+    gfx::Rect bounds = gfx::Rect(contents->GetPreferredSize());
+    bounds.set_width(std::max(0, width() - GetScrollBarWidth()));
+    contents->SetBoundsRect(bounds);
+  }
+
+ private:
+  gfx::Size fixed_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView);
+};
+
+// Container for the messages.
+class ScrollContentView : public views::View {
+ public:
+  ScrollContentView() {
+    views::BoxLayout* layout =
+        new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1);
+    layout->set_spread_blank_space(true);
+    SetLayoutManager(layout);
+  }
+
+  virtual ~ScrollContentView() {
+  }
+
+  virtual gfx::Size GetPreferredSize() OVERRIDE {
+    if (!preferred_size_.IsEmpty())
+      return preferred_size_;
+    return views::View::GetPreferredSize();
+  }
+
+  void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; }
+
+ private:
+  gfx::Size preferred_size_;
+  DISALLOW_COPY_AND_ASSIGN(ScrollContentView);
+};
+
+}  // namespace
 
 // Message Center contents.
 class MessageCenterContentsView : public views::View {
  public:
-  class ScrollContentView : public views::View {
-   public:
-    ScrollContentView() {
-      views::BoxLayout* layout =
-          new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1);
-      layout->set_spread_blank_space(true);
-      SetLayoutManager(layout);
-    }
-
-    virtual ~ScrollContentView() {
-    }
-
-    virtual gfx::Size GetPreferredSize() OVERRIDE {
-      if (!preferred_size_.IsEmpty())
-        return preferred_size_;
-      return views::View::GetPreferredSize();
-    }
-
-    void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; }
-
-   private:
-    gfx::Size preferred_size_;
-    DISALLOW_COPY_AND_ASSIGN(ScrollContentView);
-  };
-
-  explicit MessageCenterContentsView(WebNotificationTray* tray)
-      : tray_(tray) {
+  explicit MessageCenterContentsView(
+      WebNotificationList::Delegate* list_delegate)
+      : list_delegate_(list_delegate) {
     SetLayoutManager(
         new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
 
     scroll_content_ = new ScrollContentView;
-    scroller_ = new internal::FixedSizedScrollView;
-    scroller_->SetContentsView(scroll_content_);
+    scroller_ = new FixedSizedScrollView;
+    scroller_->SetContents(scroll_content_);
     AddChildView(scroller_);
 
     scroller_->SetPaintToLayer(true);
     scroller_->SetFillsBoundsOpaquely(false);
     scroller_->layer()->SetMasksToBounds(true);
 
-    button_view_ = new WebNotificationButtonView(tray);
+    button_view_ = new WebNotificationButtonView(list_delegate);
     AddChildView(button_view_);
   }
 
+  void FocusContents() {
+    scroller_->RequestFocus();
+  }
+
   void Update(const WebNotificationList::Notifications& notifications)  {
     scroll_content_->RemoveAllChildViews(true);
     scroll_content_->set_preferred_size(gfx::Size());
     size_t num_children = 0;
     for (WebNotificationList::Notifications::const_iterator iter =
              notifications.begin(); iter != notifications.end(); ++iter) {
-      WebNotificationView* view =
-          new WebNotificationView(tray_, *iter, scroller_->GetScrollBarWidth());
+      WebNotificationView* view = new WebNotificationView(
+          list_delegate_, *iter, scroller_->GetScrollBarWidth());
       view->set_scroller(scroller_);
       scroll_content_->AddChildView(view);
-      if (++num_children >= WebNotificationTray::kMaxVisibleTrayNotifications)
+      if (++num_children >=
+          WebNotificationList::kMaxVisibleMessageCenterNotifications) {
         break;
+      }
     }
     if (num_children == 0) {
       views::Label* label = new views::Label(l10n_util::GetStringUTF16(
@@ -158,7 +222,7 @@
       GetWidget()->GetRootView()->SchedulePaint();
   }
 
-  size_t NumMessageViewsForTest() const {
+  size_t NumMessageViews() const {
     return scroll_content_->child_count();
   }
 
@@ -180,8 +244,8 @@
     scroll_content_->InvalidateLayout();
   }
 
-  WebNotificationTray* tray_;
-  internal::FixedSizedScrollView* scroller_;
+  WebNotificationList::Delegate* list_delegate_;
+  FixedSizedScrollView* scroller_;
   ScrollContentView* scroll_content_;
   WebNotificationButtonView* button_view_;
 
@@ -189,37 +253,52 @@
 };
 
 // Message Center Bubble.
-MessageCenterBubble::MessageCenterBubble(WebNotificationTray* tray) :
-    WebNotificationBubble(tray),
-    contents_view_(NULL) {
-  TrayBubbleView::InitParams init_params = GetInitParams();
-  init_params.max_height = message_center::kWebNotificationBubbleMaxHeight;
-  init_params.can_activate = true;
-  views::View* anchor = tray_->tray_container();
-  bubble_view_ = TrayBubbleView::Create(
-      tray_->GetBubbleWindowContainer(), anchor, this, &init_params);
-  contents_view_ = new MessageCenterContentsView(tray);
-
-  Initialize(contents_view_);
+MessageCenterBubble::MessageCenterBubble(
+    WebNotificationList::Delegate* delegate)
+    : WebNotificationBubble(delegate),
+      contents_view_(NULL) {
 }
 
 MessageCenterBubble::~MessageCenterBubble() {}
 
-size_t MessageCenterBubble::NumMessageViewsForTest() const {
-  return contents_view_->NumMessageViewsForTest();
+TrayBubbleView::InitParams MessageCenterBubble::GetInitParams(
+    TrayBubbleView::AnchorAlignment anchor_alignment) {
+  TrayBubbleView::InitParams init_params =
+      GetDefaultInitParams(anchor_alignment);
+  init_params.max_height = message_center::kWebNotificationBubbleMaxHeight;
+  init_params.can_activate = true;
+  return init_params;
 }
 
-void MessageCenterBubble::BubbleViewDestroyed() {
+void MessageCenterBubble::InitializeContents(TrayBubbleView* bubble_view) {
+  bubble_view_ = bubble_view;
+  contents_view_ = new MessageCenterContentsView(list_delegate_);
+  bubble_view_->AddChildView(contents_view_);
+  UpdateBubbleView();
+  contents_view_->FocusContents();
+}
+
+void MessageCenterBubble::OnBubbleViewDestroyed() {
   contents_view_ = NULL;
-  WebNotificationBubble::BubbleViewDestroyed();
 }
 
 void MessageCenterBubble::UpdateBubbleView() {
-  contents_view_->Update(tray_->notification_list()->notifications());
+  if (!bubble_view_)
+    return;  // Could get called after view is closed
+  contents_view_->Update(
+      list_delegate_->GetNotificationList()->notifications());
   bubble_view_->Show();
   bubble_view_->UpdateBubble();
 }
 
-}  // namespace message_center
+void MessageCenterBubble::OnMouseEnteredView() {
+}
 
-}  // namespace ash
+void MessageCenterBubble::OnMouseExitedView() {
+}
+
+size_t MessageCenterBubble::NumMessageViewsForTest() const {
+  return contents_view_->NumMessageViews();
+}
+
+}  // namespace message_center
diff --git a/ash/system/web_notification/message_center_bubble.h b/ash/system/web_notification/message_center_bubble.h
index 33d9d68..ee7a2b72 100644
--- a/ash/system/web_notification/message_center_bubble.h
+++ b/ash/system/web_notification/message_center_bubble.h
@@ -2,35 +2,36 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_MESSAGE_CENTER_BUBBLE_H_
-#define ASH_SYSTEM_NOTIFICATION_MESSAGE_CENTER_BUBBLE_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_MESSAGE_CENTER_BUBBLE_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_MESSAGE_CENTER_BUBBLE_H_
 
+#include "ash/ash_export.h"
 #include "ash/system/web_notification/web_notification_bubble.h"
-
-namespace ash {
-
-class WebNotificationTray;
+#include "ash/system/web_notification/web_notification_list.h"
 
 namespace message_center {
 
 class MessageCenterContentsView;
 
 // Bubble for message center.
-class MessageCenterBubble : public WebNotificationBubble {
+class ASH_EXPORT MessageCenterBubble : public WebNotificationBubble {
  public:
-  explicit MessageCenterBubble(WebNotificationTray* tray);
+  explicit MessageCenterBubble(WebNotificationList::Delegate* delegate);
 
   virtual ~MessageCenterBubble();
 
+  // Overridden from WebNotificationBubble.
+  virtual TrayBubbleView::InitParams GetInitParams(
+      TrayBubbleView::AnchorAlignment anchor_alignment) OVERRIDE;
+  virtual void InitializeContents(TrayBubbleView* bubble_view) OVERRIDE;
+  virtual void OnBubbleViewDestroyed() OVERRIDE;
+  virtual void UpdateBubbleView() OVERRIDE;
+  virtual void OnMouseEnteredView() OVERRIDE;
+  virtual void OnMouseExitedView() OVERRIDE;
+
   size_t NumMessageViewsForTest() const;
 
-  // Overridden from TrayBubbleView::Delegate.
-  virtual void BubbleViewDestroyed() OVERRIDE;
-
  private:
-  // Overridden from WebNotificationBubble.
-  virtual void UpdateBubbleView() OVERRIDE;
-
   MessageCenterContentsView* contents_view_;
 
   DISALLOW_COPY_AND_ASSIGN(MessageCenterBubble);
@@ -38,6 +39,4 @@
 
 }  // namespace message_center
 
-}  // namespace ash
-
-#endif // ASH_SYSTEM_NOTIFICATION_MESSAGE_CENTER_BUBBLE_H_
+#endif // ASH_SYSTEM_WEB_NOTIFICATION_MESSAGE_CENTER_BUBBLE_H_
diff --git a/ash/system/web_notification/popup_bubble.cc b/ash/system/web_notification/popup_bubble.cc
index bbb2d8a..fabe63e 100644
--- a/ash/system/web_notification/popup_bubble.cc
+++ b/ash/system/web_notification/popup_bubble.cc
@@ -5,16 +5,11 @@
 #include "ash/system/web_notification/popup_bubble.h"
 
 #include "ash/system/tray/tray_bubble_view.h"
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/web_notification/web_notification_list.h"
-#include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/system/web_notification/web_notification_view.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
-namespace ash {
-
 namespace message_center {
 
 const int kAutocloseDelaySeconds = 5;
@@ -22,8 +17,9 @@
 // Popup notifications contents.
 class PopupBubbleContentsView : public views::View {
  public:
-  explicit PopupBubbleContentsView(WebNotificationTray* tray)
-      : tray_(tray) {
+  explicit PopupBubbleContentsView(
+      WebNotificationList::Delegate* list_delegate)
+      : list_delegate_(list_delegate) {
     SetLayoutManager(
         new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
 
@@ -42,7 +38,8 @@
     for (WebNotificationList::Notifications::const_iterator iter =
              popup_notifications.begin();
          iter != popup_notifications.end(); ++iter) {
-      WebNotificationView* view = new WebNotificationView(tray_, *iter, 0);
+      WebNotificationView* view = new WebNotificationView(
+          list_delegate_, *iter, 0);
       content_->AddChildView(view);
     }
     content_->SizeToPreferredSize();
@@ -52,73 +49,73 @@
       GetWidget()->GetRootView()->SchedulePaint();
   }
 
-  size_t NumMessageViewsForTest() const {
+  size_t NumMessageViews() const {
     return content_->child_count();
   }
 
  private:
-  WebNotificationTray* tray_;
+  WebNotificationList::Delegate* list_delegate_;
   views::View* content_;
 
   DISALLOW_COPY_AND_ASSIGN(PopupBubbleContentsView);
 };
 
 // PopupBubble
-PopupBubble::PopupBubble(WebNotificationTray* tray) :
-    WebNotificationBubble(tray),
+PopupBubble::PopupBubble(WebNotificationList::Delegate* delegate) :
+    WebNotificationBubble(delegate),
     contents_view_(NULL),
-    num_popups_(0),
-    dirty_(false) {
-  TrayBubbleView::InitParams init_params = GetInitParams();
+    num_popups_(0) {
+}
+
+PopupBubble::~PopupBubble() {
+}
+
+TrayBubbleView::InitParams PopupBubble::GetInitParams(
+    TrayBubbleView::AnchorAlignment anchor_alignment) {
+  TrayBubbleView::InitParams init_params =
+      GetDefaultInitParams(anchor_alignment);
   init_params.top_color = kBackgroundColor;
   init_params.arrow_color = kBackgroundColor;
   init_params.close_on_deactivate = false;
-  views::View* anchor = tray_->tray_container();
-  bubble_view_ = TrayBubbleView::Create(
-      tray_->GetBubbleWindowContainer(), anchor, this, &init_params);
-  contents_view_ = new PopupBubbleContentsView(tray);
-
-  Initialize(contents_view_);
+  return init_params;
 }
 
-PopupBubble::~PopupBubble() {}
-
-size_t PopupBubble::NumMessageViewsForTest() const {
-  return contents_view_->NumMessageViewsForTest();
+void PopupBubble::InitializeContents(TrayBubbleView* bubble_view) {
+  bubble_view_ = bubble_view;
+  contents_view_ = new PopupBubbleContentsView(list_delegate_);
+  bubble_view_->AddChildView(contents_view_);
+  UpdateBubbleView();
 }
 
-void PopupBubble::BubbleViewDestroyed() {
+void PopupBubble::OnBubbleViewDestroyed() {
   contents_view_ = NULL;
-  WebNotificationBubble::BubbleViewDestroyed();
-}
-
-void PopupBubble::OnMouseEnteredView() {
-  StopAutoCloseTimer();
-  WebNotificationBubble::OnMouseEnteredView();
-}
-
-void PopupBubble::OnMouseExitedView() {
-  StartAutoCloseTimer();
-  WebNotificationBubble::OnMouseExitedView();
 }
 
 void PopupBubble::UpdateBubbleView() {
   WebNotificationList::Notifications popup_notifications;
-  tray_->notification_list()->GetPopupNotifications(&popup_notifications);
+  list_delegate_->GetNotificationList()->GetPopupNotifications(
+      &popup_notifications);
   if (popup_notifications.size() == 0) {
-    tray_->HideBubbleWithView(bubble_view());  // deletes |this|
+    if (bubble_view())
+      bubble_view()->delegate()->HideBubble(bubble_view());  // deletes |this|
     return;
   }
-  // Only update the popup tray if the number of visible popup notifications
-  // has changed.
-  if (popup_notifications.size() != num_popups_ || dirty()) {
-    set_dirty(false);
+  // Only reset the timer when the number of visible notifications changes.
+  if (num_popups_ != popup_notifications.size()) {
     num_popups_ = popup_notifications.size();
-    contents_view_->Update(popup_notifications);
-    bubble_view_->Show();
-    bubble_view_->UpdateBubble();
     StartAutoCloseTimer();
   }
+  contents_view_->Update(popup_notifications);
+  bubble_view_->Show();
+  bubble_view_->UpdateBubble();
+}
+
+void PopupBubble::OnMouseEnteredView() {
+  StopAutoCloseTimer();
+}
+
+void PopupBubble::OnMouseExitedView() {
+  StartAutoCloseTimer();
 }
 
 void PopupBubble::StartAutoCloseTimer() {
@@ -133,11 +130,13 @@
 }
 
 void PopupBubble::OnAutoClose() {
-  tray_->notification_list()->MarkPopupsAsShown();
+  list_delegate_->GetNotificationList()->MarkPopupsAsShown();
   num_popups_ = 0;
   UpdateBubbleView();
 }
 
-}  // namespace message_center
+size_t PopupBubble::NumMessageViewsForTest() const {
+  return contents_view_->NumMessageViews();
+}
 
-}  // namespace ash
+}  // namespace message_center
diff --git a/ash/system/web_notification/popup_bubble.h b/ash/system/web_notification/popup_bubble.h
index 747776e..5ece865 100644
--- a/ash/system/web_notification/popup_bubble.h
+++ b/ash/system/web_notification/popup_bubble.h
@@ -2,57 +2,49 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_POPUP_BUBBLE_H_
-#define ASH_SYSTEM_NOTIFICATION_POPUP_BUBBLE_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_POPUP_BUBBLE_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_POPUP_BUBBLE_H_
 
+#include "ash/ash_export.h"
 #include "ash/system/web_notification/web_notification_bubble.h"
+#include "ash/system/web_notification/web_notification_list.h"
 #include "base/timer.h"
 
-namespace ash {
-
-class WebNotificationTray;
-
 namespace message_center {
 
 class PopupBubbleContentsView;
 
 // Bubble for popup notifications.
-class PopupBubble : public WebNotificationBubble {
+class ASH_EXPORT PopupBubble : public WebNotificationBubble {
  public:
-  explicit PopupBubble(WebNotificationTray* tray);
+  explicit PopupBubble(WebNotificationList::Delegate* delegate);
 
   virtual ~PopupBubble();
 
-  size_t NumMessageViewsForTest() const;
+  void StartAutoCloseTimer();
+  void StopAutoCloseTimer();
 
-  bool dirty() const { return dirty_; }
-  void set_dirty(bool dirty) { dirty_ = dirty; }
-
-  // Overridden from TrayBubbleView::Delegate.
-  virtual void BubbleViewDestroyed() OVERRIDE;
+  // Overridden from WebNotificationBubble.
+  virtual TrayBubbleView::InitParams GetInitParams(
+      TrayBubbleView::AnchorAlignment anchor_alignment) OVERRIDE;
+  virtual void InitializeContents(TrayBubbleView* bubble_view) OVERRIDE;
+  virtual void OnBubbleViewDestroyed() OVERRIDE;
+  virtual void UpdateBubbleView() OVERRIDE;
   virtual void OnMouseEnteredView() OVERRIDE;
   virtual void OnMouseExitedView() OVERRIDE;
 
+   size_t NumMessageViewsForTest() const;
+
  private:
-  // Overridden from WebNotificationBubble.
-  virtual void UpdateBubbleView() OVERRIDE;
-
-  void StartAutoCloseTimer();
-
-  void StopAutoCloseTimer();
-
   void OnAutoClose();
 
   base::OneShotTimer<PopupBubble> autoclose_;
   PopupBubbleContentsView* contents_view_;
   size_t num_popups_;
-  bool dirty_;
 
   DISALLOW_COPY_AND_ASSIGN(PopupBubble);
 };
 
 }  // namespace message_center
 
-}  // namespace ash
-
-#endif // ASH_SYSTEM_NOTIFICATION_POPUP_BUBBLE_H_
+#endif // ASH_SYSTEM_WEB_NOTIFICATION_POPUP_BUBBLE_H_
diff --git a/ash/system/web_notification/web_notification.cc b/ash/system/web_notification/web_notification.cc
index 3a60669..9390d18 100644
--- a/ash/system/web_notification/web_notification.cc
+++ b/ash/system/web_notification/web_notification.cc
@@ -4,8 +4,6 @@
 
 #include "ash/system/web_notification/web_notification.h"
 
-namespace ash {
-
 namespace message_center {
 
 WebNotification::WebNotification() : is_read(false),
@@ -16,5 +14,3 @@
 }
 
 }  // namespace message_center
-
-}  // namespace ash
diff --git a/ash/system/web_notification/web_notification.h b/ash/system/web_notification/web_notification.h
index 8380f57d..15b49ea 100644
--- a/ash/system/web_notification/web_notification.h
+++ b/ash/system/web_notification/web_notification.h
@@ -2,16 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_H_
-#define ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_H_
 
 #include <string>
 
 #include "base/string16.h"
 #include "ui/gfx/image/image_skia.h"
 
-namespace ash {
-
 namespace message_center {
 
 struct WebNotification {
@@ -30,6 +28,4 @@
 
 }  // namespace message_center
 
-}  // namespace ash
-
-#endif // ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_H_
+#endif // ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_H_
diff --git a/ash/system/web_notification/web_notification_bubble.cc b/ash/system/web_notification/web_notification_bubble.cc
index a99bc7c..657a8ed2 100644
--- a/ash/system/web_notification/web_notification_bubble.cc
+++ b/ash/system/web_notification/web_notification_bubble.cc
@@ -4,34 +4,32 @@
 
 #include "ash/system/web_notification/web_notification_bubble.h"
 
-#include "ash/system/tray/tray_bubble_wrapper.h"
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/system/web_notification/web_notification_view.h"
 #include "base/bind.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
-namespace ash {
-
-namespace message_center {
-
+namespace {
 // Delay laying out the WebNotificationBubble until all notifications have been
 // added and icons have had a chance to load.
 const int kUpdateDelayMs = 50;
-
-WebNotificationBubble::WebNotificationBubble(WebNotificationTray* tray)
-    : tray_(tray),
-      bubble_view_(NULL),
-      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+const int kNotificationBubbleWidth = 300;
 }
 
-void WebNotificationBubble::Initialize(views::View* contents_view) {
-  DCHECK(bubble_view_);
-  bubble_view_->AddChildView(contents_view);
+namespace message_center {
 
-  bubble_wrapper_.reset(new internal::TrayBubbleWrapper(tray_, bubble_view_));
-  UpdateBubbleView();
+const SkColor WebNotificationBubble::kBackgroundColor =
+    SkColorSetRGB(0xfe, 0xfe, 0xfe);
+const SkColor WebNotificationBubble::kHeaderBackgroundColorLight =
+    SkColorSetRGB(0xf1, 0xf1, 0xf1);
+const SkColor WebNotificationBubble::kHeaderBackgroundColorDark =
+    SkColorSetRGB(0xe7, 0xe7, 0xe7);
+
+WebNotificationBubble::WebNotificationBubble(
+    WebNotificationList::Delegate* list_delegate)
+    : list_delegate_(list_delegate),
+      bubble_view_(NULL),
+      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
 }
 
 WebNotificationBubble::~WebNotificationBubble() {
@@ -39,6 +37,11 @@
     bubble_view_->reset_delegate();
 }
 
+void WebNotificationBubble::BubbleViewDestroyed() {
+  bubble_view_ = NULL;
+  OnBubbleViewDestroyed();
+}
+
 void WebNotificationBubble::ScheduleUpdate() {
   weak_ptr_factory_.InvalidateWeakPtrs();  // Cancel any pending update.
   MessageLoop::current()->PostDelayedTask(
@@ -52,46 +55,15 @@
   return bubble_view() && bubble_view()->GetWidget()->IsVisible();
 }
 
-void WebNotificationBubble::BubbleViewDestroyed() {
-  bubble_view_ = NULL;
-}
-
-void WebNotificationBubble::OnMouseEnteredView() {
-}
-
-void WebNotificationBubble::OnMouseExitedView() {
-}
-
-string16 WebNotificationBubble::GetAccessibleName() {
-  return tray_->GetAccessibleName();
-}
-
-gfx::Rect WebNotificationBubble::GetAnchorRect(
-    views::Widget* anchor_widget,
-    TrayBubbleView::AnchorType anchor_type,
+TrayBubbleView::InitParams WebNotificationBubble::GetDefaultInitParams(
     TrayBubbleView::AnchorAlignment anchor_alignment) {
-  return tray_->GetAnchorRect(anchor_widget, anchor_type, anchor_alignment);
-}
-
-TrayBubbleView::InitParams WebNotificationBubble::GetInitParams() {
-  TrayBubbleView::AnchorAlignment anchor_alignment =
-      tray_->GetAnchorAlignment();
   TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
                                          anchor_alignment,
-                                         kTrayPopupWidth);
+                                         kNotificationBubbleWidth);
   init_params.top_color = kBackgroundColor;
   init_params.arrow_color = kHeaderBackgroundColorDark;
   init_params.bubble_width = kWebNotificationWidth;
-  if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
-    views::View* anchor = tray_->tray_container();
-    gfx::Point bounds(anchor->width() / 2, 0);
-
-    views::View::ConvertPointToWidget(anchor, &bounds);
-    init_params.arrow_offset = bounds.x();
-  }
   return init_params;
 }
 
 }  // namespace message_center
-
-}  // namespace ash
diff --git a/ash/system/web_notification/web_notification_bubble.h b/ash/system/web_notification/web_notification_bubble.h
index d706144..3485f6c 100644
--- a/ash/system/web_notification/web_notification_bubble.h
+++ b/ash/system/web_notification/web_notification_bubble.h
@@ -2,36 +2,47 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
-#define ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
 
+#include "ash/ash_export.h"
 #include "ash/system/tray/tray_bubble_view.h"
+#include "ash/system/web_notification/web_notification_list.h"
 #include "base/memory/scoped_ptr.h"
 
-namespace ash {
-
-class WebNotificationTray;
-
-namespace internal {
-class TrayBubbleWrapper;
-}
-
 namespace message_center {
 
 class WebNotificationContentsView;
 class WebNotificationView;
 
-class WebNotificationBubble : public TrayBubbleView::Delegate {
+class ASH_EXPORT WebNotificationBubble {
  public:
-  explicit WebNotificationBubble(WebNotificationTray* tray);
+  explicit WebNotificationBubble(WebNotificationList::Delegate* list_delegate);
 
   virtual ~WebNotificationBubble();
 
-  void Initialize(views::View* contents_view);
+  // Gets called when when the bubble view associated with this bubble is
+  // destroyed. Clears |bubble_view_| and calls OnBubbleViewDestroyed.
+  void BubbleViewDestroyed();
+
+  // Gets the init params for the implementation.
+  virtual TrayBubbleView::InitParams GetInitParams(
+      TrayBubbleView::AnchorAlignment anchor_alignment) = 0;
+
+  // Called after the bubble view has been constructed. Creates and initializes
+  // the bubble contents.
+  virtual void InitializeContents(TrayBubbleView* bubble_view) = 0;
+
+  // Called from BubbleViewDestroyed for implementation specific details.
+  virtual void OnBubbleViewDestroyed() = 0;
 
   // Updates the bubble; implementation dependent.
   virtual void UpdateBubbleView() = 0;
 
+  // Called when the mouse enters/exists the view.
+  virtual void OnMouseEnteredView() = 0;
+  virtual void OnMouseExitedView() = 0;
+
   // Schedules bubble for layout after all notifications have been
   // added and icons have had a chance to load.
   void ScheduleUpdate();
@@ -40,21 +51,16 @@
 
   TrayBubbleView* bubble_view() const { return bubble_view_; }
 
-  // Overridden from TrayBubbleView::Delegate.
-  virtual void BubbleViewDestroyed() OVERRIDE;
-  virtual void OnMouseEnteredView() OVERRIDE;
-  virtual void OnMouseExitedView() OVERRIDE;
-  virtual string16 GetAccessibleName() OVERRIDE;
-  virtual gfx::Rect GetAnchorRect(views::Widget* anchor_widget,
-                                  AnchorType anchor_type,
-                                  AnchorAlignment anchor_alignment) OVERRIDE;
+  static const SkColor kBackgroundColor;
+  static const SkColor kHeaderBackgroundColorLight;
+  static const SkColor kHeaderBackgroundColorDark;
 
  protected:
-  TrayBubbleView::InitParams GetInitParams();
+  TrayBubbleView::InitParams GetDefaultInitParams(
+      TrayBubbleView::AnchorAlignment anchor_alignment);
 
-  WebNotificationTray* tray_;
+  WebNotificationList::Delegate* list_delegate_;
   TrayBubbleView* bubble_view_;
-  scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
   base::WeakPtrFactory<WebNotificationBubble> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WebNotificationBubble);
@@ -62,6 +68,4 @@
 
 }  // namespace message_center
 
-}  // namespace ash
-
-#endif // ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
+#endif // ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
diff --git a/ash/system/web_notification/web_notification_list.cc b/ash/system/web_notification/web_notification_list.cc
index 1190ddf..cd66a25 100644
--- a/ash/system/web_notification/web_notification_list.cc
+++ b/ash/system/web_notification/web_notification_list.cc
@@ -4,14 +4,14 @@
 
 #include "ash/system/web_notification/web_notification_list.h"
 
-#include "ash/system/web_notification/web_notification_tray.h"
-
-namespace ash {
-
 namespace message_center {
 
-WebNotificationList::WebNotificationList()
-    : message_center_visible_(false),
+const size_t WebNotificationList::kMaxVisibleMessageCenterNotifications = 100;
+const size_t WebNotificationList::kMaxVisiblePopupNotifications = 5;
+
+WebNotificationList::WebNotificationList(Delegate* delegate)
+    : delegate_(delegate),
+      message_center_visible_(false),
       unread_count_(0) {
 }
 
@@ -77,7 +77,6 @@
 }
 
 void WebNotificationList::SendRemoveNotificationsBySource(
-    WebNotificationTray* tray,
     const std::string& id) {
   Notifications::iterator source_iter = GetNotification(id);
   if (source_iter == notifications_.end())
@@ -87,12 +86,11 @@
        loopiter != notifications_.end(); ) {
     Notifications::iterator curiter = loopiter++;
     if (curiter->display_source == display_source)
-      tray->SendRemoveNotification(curiter->id);
+      delegate_->SendRemoveNotification(curiter->id);
   }
 }
 
 void WebNotificationList::SendRemoveNotificationsByExtension(
-    WebNotificationTray* tray,
     const std::string& id) {
   Notifications::iterator source_iter = GetNotification(id);
   if (source_iter == notifications_.end())
@@ -102,7 +100,7 @@
        loopiter != notifications_.end(); ) {
     Notifications::iterator curiter = loopiter++;
     if (curiter->extension_id == extension_id)
-      tray->SendRemoveNotification(curiter->id);
+      delegate_->SendRemoveNotification(curiter->id);
   }
 }
 
@@ -182,7 +180,7 @@
     if (last->shown_as_popup)
       break;
     ++last;
-    if (popup_count < WebNotificationTray::kMaxVisiblePopupNotifications)
+    if (popup_count < kMaxVisiblePopupNotifications)
       ++popup_count;
     else
       ++first;
@@ -190,5 +188,3 @@
 }
 
 }  // namespace message_center
-
-}  // namespace ash
diff --git a/ash/system/web_notification/web_notification_list.h b/ash/system/web_notification/web_notification_list.h
index a7a78ab..4fb24161 100644
--- a/ash/system/web_notification/web_notification_list.h
+++ b/ash/system/web_notification/web_notification_list.h
@@ -2,26 +2,46 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_LIST_H_
-#define ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_LIST_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_LIST_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_LIST_H_
 
 #include <list>
 #include <string>
 
+#include "ash/ash_export.h"
 #include "ash/system/web_notification/web_notification.h"
 
-namespace ash {
-
-class WebNotificationTray;
-
 namespace message_center {
 
 // A helper class to manage the list of notifications.
-class WebNotificationList {
+class ASH_EXPORT WebNotificationList {
  public:
   typedef std::list<WebNotification> Notifications;
 
-  WebNotificationList();
+  class ASH_EXPORT Delegate {
+   public:
+    Delegate() {}
+    virtual ~Delegate() {}
+
+    // Removes notifications
+    virtual void SendRemoveNotification(const std::string& id) = 0;
+    virtual void SendRemoveAllNotifications() = 0;
+
+    // Disables notifications
+    virtual void DisableNotificationByExtension(const std::string& id) = 0;
+    virtual void DisableNotificationByUrl(const std::string& id) = 0;
+
+    // Requests the Delegate to the settings dialog.
+    virtual void ShowNotificationSettings(const std::string& id) = 0;
+
+    // Called when a notification is clicked on.
+    virtual void OnNotificationClicked(const std::string& id) = 0;
+
+    // Returns the list of notifications to display.
+    virtual WebNotificationList* GetNotificationList() = 0;
+  };
+
+  explicit WebNotificationList(Delegate* delegate);
   virtual ~WebNotificationList();
 
   void SetMessageCenterVisible(bool visible);
@@ -42,11 +62,9 @@
 
   void RemoveAllNotifications();
 
-  void SendRemoveNotificationsBySource(WebNotificationTray* tray,
-                                       const std::string& id);
+  void SendRemoveNotificationsBySource(const std::string& id);
 
-  void SendRemoveNotificationsByExtension(WebNotificationTray* tray,
-                                          const std::string& id);
+  void SendRemoveNotificationsByExtension(const std::string& id);
 
   // Returns true if the notification exists and was updated.
   bool SetNotificationImage(const std::string& id,
@@ -68,6 +86,9 @@
   const Notifications& notifications() const { return notifications_; }
   int unread_count() const { return unread_count_; }
 
+  static const size_t kMaxVisiblePopupNotifications;
+  static const size_t kMaxVisibleMessageCenterNotifications;
+
  private:
   // Iterates through the list and returns the first notification matching |id|
   // (should always be unique).
@@ -82,6 +103,7 @@
   void GetPopupIterators(Notifications::iterator& first,
                          Notifications::iterator& last);
 
+  Delegate* delegate_;
   Notifications notifications_;
   bool message_center_visible_;
   int unread_count_;
@@ -91,6 +113,4 @@
 
 }  // namespace message_center
 
-}  // namespace ash
-
-#endif // ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_LIST_H_
+#endif // ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_LIST_H_
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index baf9f01..5372451 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -7,6 +7,7 @@
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/tray_bubble_view.h"
+#include "ash/system/tray/tray_bubble_wrapper.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_views.h"
 #include "ash/system/web_notification/message_center_bubble.h"
@@ -14,7 +15,6 @@
 #include "ash/system/web_notification/web_notification.h"
 #include "ash/system/web_notification/web_notification_bubble.h"
 #include "ash/system/web_notification/web_notification_list.h"
-#include "ash/system/web_notification/web_notification_view.h"
 #include "ash/wm/shelf_layout_manager.h"
 #include "base/message_loop.h"
 #include "base/stringprintf.h"
@@ -43,30 +43,63 @@
 
 }  // namespace
 
-namespace ash {
-
-// WebNotificationTray statics (for unit tests)
-
-// Limit the number of visible notifications.
-const size_t WebNotificationTray::kMaxVisibleTrayNotifications = 100;
-const size_t WebNotificationTray::kMaxVisiblePopupNotifications = 5;
-
 using message_center::MessageCenterBubble;
 using message_center::PopupBubble;
+using message_center::TrayBubbleView;
 using message_center::WebNotification;
 using message_center::WebNotificationBubble;
 using message_center::WebNotificationList;
-using message_center::WebNotificationView;
+
+namespace ash {
+
+namespace internal {
+
+// Class to initialize and manage the WebNotificationBubble and
+// TrayBubbleWrapper instances for a bubble.
+
+class WebNotificationBubbleWrapper {
+ public:
+  // Takes ownership of |bubble| and creates |bubble_wrapper_|.
+  WebNotificationBubbleWrapper(WebNotificationTray* tray,
+                               WebNotificationBubble* bubble) {
+    bubble_.reset(bubble);
+    TrayBubbleView::AnchorAlignment anchor_alignment =
+        tray->GetAnchorAlignment();
+    TrayBubbleView::InitParams init_params =
+        bubble->GetInitParams(anchor_alignment);
+    views::View* anchor = tray->tray_container();
+    if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
+      gfx::Point bounds(anchor->width() / 2, 0);
+      views::View::ConvertPointToWidget(anchor, &bounds);
+      init_params.arrow_offset = bounds.x();
+    }
+    TrayBubbleView* bubble_view = TrayBubbleView::Create(
+        tray->GetBubbleWindowContainer(), anchor, tray, &init_params);
+    bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_view));
+    bubble->InitializeContents(bubble_view);
+  }
+
+  WebNotificationBubble* bubble() const { return bubble_.get(); }
+
+  // Convenience accessors.
+  TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); }
+
+ private:
+  scoped_ptr<WebNotificationBubble> bubble_;
+  scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
+};
+
+}  // namespace internal
 
 WebNotificationTray::WebNotificationTray(
     internal::StatusAreaWidget* status_area_widget)
     : internal::TrayBackgroundView(status_area_widget),
-      notification_list_(new WebNotificationList()),
       button_(NULL),
       delegate_(NULL),
       show_message_center_on_unlock_(false) {
-  button_ = new views::ImageButton(this);
+  notification_list_.reset(new WebNotificationList(this));
 
+  button_ = new views::ImageButton(this);
   tray_container()->AddChildView(button_);
 
   UpdateTray();
@@ -120,8 +153,6 @@
   if (!notification_list_->SetNotificationImage(id, image))
     return;
   UpdateTrayAndBubble();
-  if (popup_bubble())
-    popup_bubble()->set_dirty(true);
   ShowPopupBubble();
 }
 
@@ -136,7 +167,10 @@
   notification_list_->SetMessageCenterVisible(true);
   UpdateTray();
   HidePopupBubble();
-  message_center_bubble_.reset(new MessageCenterBubble(this));
+  MessageCenterBubble* bubble = new MessageCenterBubble(this);
+  message_center_bubble_.reset(
+      new internal::WebNotificationBubbleWrapper(this, bubble));
+
   status_area_widget()->SetHideSystemNotifications(true);
   GetShelfLayoutManager()->UpdateAutoHideState();
 }
@@ -168,9 +202,11 @@
     return;
   UpdateTray();
   if (popup_bubble()) {
-    popup_bubble()->ScheduleUpdate();
+    popup_bubble()->bubble()->ScheduleUpdate();
   } else if (notification_list_->HasPopupNotifications()) {
-    popup_bubble_.reset(new PopupBubble(this));
+    popup_bubble_.reset(
+        new internal::WebNotificationBubbleWrapper(
+            this, new PopupBubble(this)));
   }
 }
 
@@ -195,7 +231,8 @@
 }
 
 bool WebNotificationTray::IsMessageCenterBubbleVisible() const {
-  return (message_center_bubble() && message_center_bubble_->IsVisible());
+  return (message_center_bubble() &&
+          message_center_bubble_->bubble()->IsVisible());
 }
 
 bool WebNotificationTray::IsMouseInNotificationBubble() const {
@@ -224,13 +261,11 @@
     message_center_bubble_->bubble_view()->UpdateBubble();
 }
 
-string16 WebNotificationTray::GetAccessibleName() {
+string16 WebNotificationTray::GetAccessibleNameForTray() {
   return l10n_util::GetStringUTF16(
       IDS_ASH_WEB_NOTIFICATION_TRAY_ACCESSIBLE_NAME);
 }
 
-// Private methods invoked by WebNotificationBubble and its child classes
-
 void WebNotificationTray::SendRemoveNotification(const std::string& id) {
   // If this is the only notification in the list, close the bubble.
   if (notification_list_->notifications().size() == 1 &&
@@ -259,18 +294,43 @@
 
 // When we disable notifications, we remove any existing matching
 // notifications to avoid adding complicated UI to re-enable the source.
-void WebNotificationTray::DisableByExtension(const std::string& id) {
+void WebNotificationTray::DisableNotificationByExtension(
+    const std::string& id) {
   if (delegate_)
     delegate_->DisableExtension(id);
   // Will call SendRemoveNotification for each matching notification.
-  notification_list_->SendRemoveNotificationsByExtension(this, id);
+  notification_list_->SendRemoveNotificationsByExtension(id);
 }
 
-void WebNotificationTray::DisableByUrl(const std::string& id) {
+void WebNotificationTray::DisableNotificationByUrl(const std::string& id) {
   if (delegate_)
     delegate_->DisableNotificationsFromSource(id);
   // Will call SendRemoveNotification for each matching notification.
-  notification_list_->SendRemoveNotificationsBySource(this, id);
+  notification_list_->SendRemoveNotificationsBySource(id);
+}
+
+void WebNotificationTray::ShowNotificationSettings(const std::string& id) {
+  if (delegate_)
+    delegate_->ShowSettings(id);
+}
+
+void WebNotificationTray::OnNotificationClicked(const std::string& id) {
+  if (delegate_)
+    delegate_->OnClicked(id);
+}
+
+WebNotificationList* WebNotificationTray::GetNotificationList() {
+  return notification_list_.get();
+}
+
+void WebNotificationTray::HideBubbleWithView(
+    const TrayBubbleView* bubble_view) {
+  if (message_center_bubble() &&
+      bubble_view == message_center_bubble()->bubble_view()) {
+    HideMessageCenterBubble();
+  } else if (popup_bubble() && bubble_view == popup_bubble()->bubble_view()) {
+    HidePopupBubble();
+  }
 }
 
 bool WebNotificationTray::PerformAction(const ui::Event& event) {
@@ -278,23 +338,44 @@
   return true;
 }
 
+void WebNotificationTray::BubbleViewDestroyed() {
+  if (message_center_bubble())
+    message_center_bubble()->bubble()->BubbleViewDestroyed();
+  if (popup_bubble())
+    popup_bubble()->bubble()->BubbleViewDestroyed();
+}
+
+void WebNotificationTray::OnMouseEnteredView() {
+  if (popup_bubble())
+    popup_bubble()->bubble()->OnMouseEnteredView();
+}
+
+void WebNotificationTray::OnMouseExitedView() {
+  if (popup_bubble())
+    popup_bubble()->bubble()->OnMouseExitedView();
+}
+
+string16 WebNotificationTray::GetAccessibleNameForBubble() {
+  return GetAccessibleNameForTray();
+}
+
+gfx::Rect WebNotificationTray::GetAnchorRect(views::Widget* anchor_widget,
+                                             AnchorType anchor_type,
+                                             AnchorAlignment anchor_alignment) {
+  return GetBubbleAnchorRect(anchor_widget, anchor_type, anchor_alignment);
+}
+
+void WebNotificationTray::HideBubble(const TrayBubbleView* bubble_view) {
+  HideBubbleWithView(bubble_view);
+}
+
 void WebNotificationTray::ButtonPressed(views::Button* sender,
                                         const ui::Event& event) {
   DCHECK(sender == button_);
   ToggleMessageCenterBubble();
 }
 
-void WebNotificationTray::ShowSettings(const std::string& id) {
-  if (delegate_)
-    delegate_->ShowSettings(id);
-}
-
-void WebNotificationTray::OnClicked(const std::string& id) {
-  if (delegate_)
-    delegate_->OnClicked(id);
-}
-
-// Other private methods
+// Private methods
 
 void WebNotificationTray::ToggleMessageCenterBubble() {
   if (message_center_bubble())
@@ -339,27 +420,17 @@
     if (notification_list_->notifications().size() == 0)
       HideMessageCenterBubble();
     else
-      message_center_bubble()->ScheduleUpdate();
+      message_center_bubble()->bubble()->ScheduleUpdate();
   }
   if (popup_bubble()) {
     if (notification_list_->notifications().size() == 0)
       HidePopupBubble();
     else
-      popup_bubble()->ScheduleUpdate();
+      popup_bubble()->bubble()->ScheduleUpdate();
   }
   UpdateTray();
 }
 
-void WebNotificationTray::HideBubbleWithView(
-    const TrayBubbleView* bubble_view) {
-  if (message_center_bubble() &&
-      bubble_view == message_center_bubble()->bubble_view()) {
-    HideMessageCenterBubble();
-  } else if (popup_bubble() && bubble_view == popup_bubble()->bubble_view()) {
-    HidePopupBubble();
-  }
-}
-
 bool WebNotificationTray::ClickedOutsideBubble() {
   // Only hide the message center.
   if (!message_center_bubble())
@@ -370,28 +441,16 @@
 
 // Methods for testing
 
-size_t WebNotificationTray::GetNotificationCountForTest() const {
-  return notification_list_->notifications().size();
+MessageCenterBubble* WebNotificationTray::GetMessageCenterBubbleForTest() {
+  if (!message_center_bubble_.get())
+    return NULL;
+  return static_cast<MessageCenterBubble*>(message_center_bubble_->bubble());
 }
 
-bool WebNotificationTray::HasNotificationForTest(const std::string& id) const {
-  return notification_list_->HasNotification(id);
-}
-
-void WebNotificationTray::RemoveAllNotificationsForTest() {
-  notification_list_->RemoveAllNotifications();
-}
-
-size_t WebNotificationTray::GetMessageCenterNotificationCountForTest() const {
-  if (!message_center_bubble())
-    return 0;
-  return message_center_bubble()->NumMessageViewsForTest();
-}
-
-size_t WebNotificationTray::GetPopupNotificationCountForTest() const {
-  if (!popup_bubble())
-    return 0;
-  return popup_bubble()->NumMessageViewsForTest();
+PopupBubble* WebNotificationTray::GetPopupBubbleForTest() {
+  if (!popup_bubble_.get())
+    return NULL;
+  return static_cast<PopupBubble*>(popup_bubble_->bubble());
 }
 
 }  // namespace ash
diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h
index 64d2aff..abf42001 100644
--- a/ash/system/web_notification/web_notification_tray.h
+++ b/ash/system/web_notification/web_notification_tray.h
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
-#define ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
 
 #include "ash/ash_export.h"
 #include "ash/system/tray/tray_background_view.h"
 #include "ash/system/tray/tray_views.h"
 #include "ash/system/user/login_status.h"
+#include "ash/system/web_notification/web_notification_list.h"
 #include "base/gtest_prod_util.h"
 
 namespace aura {
@@ -23,20 +24,16 @@
 class ImageButton;
 }
 
+namespace message_center {
+class MessageCenterBubble;
+class PopupBubble;
+}
+
 namespace ash {
 
 namespace internal {
 class StatusAreaWidget;
-}
-
-namespace message_center {
-class MessageCenterBubble;
-class PopupBubble;
-class WebNotificationBubble;
-class WebNotificationButtonView;
-class WebNotificationList;
-class WebNotificationMenuModel;
-class WebNotificationView;
+class WebNotificationBubbleWrapper;
 }
 
 // Status area tray for showing browser and app notifications. The client
@@ -49,10 +46,13 @@
 // generated by SystemTrayItem). Visibility of one notification type or other
 // is controlled by StatusAreaWidget.
 
-class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView,
-                                       public views::ButtonListener {
+class ASH_EXPORT WebNotificationTray
+    : public internal::TrayBackgroundView,
+      public message_center::TrayBubbleView::Delegate,
+      public message_center::WebNotificationList::Delegate,
+      public views::ButtonListener {
  public:
-  class Delegate {
+  class ASH_EXPORT Delegate {
    public:
     virtual ~Delegate() {}
 
@@ -123,51 +123,45 @@
   // Overridden from TrayBackgroundView.
   virtual void SetShelfAlignment(ShelfAlignment alignment) OVERRIDE;
   virtual void AnchorUpdated() OVERRIDE;
-  virtual string16 GetAccessibleName() OVERRIDE;
-  virtual void HideBubbleWithView(const TrayBubbleView* bubble_view) OVERRIDE;
+  virtual string16 GetAccessibleNameForTray() OVERRIDE;
+  virtual void HideBubbleWithView(
+      const message_center::TrayBubbleView* bubble_view) OVERRIDE;
   virtual bool ClickedOutsideBubble() OVERRIDE;
 
   // Overridden from internal::ActionableView.
   virtual bool PerformAction(const ui::Event& event) OVERRIDE;
 
+  // Overridden from message_center::TrayBubbleView::Delegate.
+  virtual void BubbleViewDestroyed() OVERRIDE;
+  virtual void OnMouseEnteredView() OVERRIDE;
+  virtual void OnMouseExitedView() OVERRIDE;
+  virtual string16 GetAccessibleNameForBubble() OVERRIDE;
+  virtual gfx::Rect GetAnchorRect(views::Widget* anchor_widget,
+                                  AnchorType anchor_type,
+                                  AnchorAlignment anchor_alignment) OVERRIDE;
+  virtual void HideBubble(
+      const message_center::TrayBubbleView* bubble_view) OVERRIDE;
+
+  // Overridden from message_center::WebNotificationList::Delegate.
+  virtual void SendRemoveNotification(const std::string& id) OVERRIDE;
+  virtual void SendRemoveAllNotifications() OVERRIDE;
+  virtual void DisableNotificationByExtension(const std::string& id) OVERRIDE;
+  virtual void DisableNotificationByUrl(const std::string& id) OVERRIDE;
+  virtual void ShowNotificationSettings(const std::string& id) OVERRIDE;
+  virtual void OnNotificationClicked(const std::string& id) OVERRIDE;
+  virtual message_center::WebNotificationList* GetNotificationList() OVERRIDE;
+
   // Overridden from ButtonListener.
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE;
 
-  // Constants exposed for unit tests:
-  static const size_t kMaxVisibleTrayNotifications;
-  static const size_t kMaxVisiblePopupNotifications;
-
  private:
-  friend class message_center::MessageCenterBubble;
-  friend class message_center::PopupBubble;
-  friend class message_center::WebNotificationBubble;
-  friend class message_center::WebNotificationButtonView;
-  friend class message_center::WebNotificationList;
-  friend class message_center::WebNotificationMenuModel;
-  friend class message_center::WebNotificationView;
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotifications);
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotificationPopupBubble);
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest,
                            ManyMessageCenterNotifications);
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, ManyPopupNotifications);
 
-  // Sends a remove request to the delegate.
-  void SendRemoveNotification(const std::string& id);
-
-  // Sends a remove request for all notifications to the delegate.
-  void SendRemoveAllNotifications();
-
-  // Disables all notifications matching notification |id|.
-  void DisableByExtension(const std::string& id);
-  void DisableByUrl(const std::string& id);
-
-  // Requests the Delegate to the settings dialog.
-  void ShowSettings(const std::string& id);
-
-  // Called when a notification is clicked on. Event is passed to the Delegate.
-  void OnClicked(const std::string& id);
-
   // Shows or hides the message center bubble.
   void ToggleMessageCenterBubble();
 
@@ -189,26 +183,25 @@
   // As above but also updates any visible bubble.
   void UpdateTrayAndBubble();
 
-  // Testing accessors.
-  size_t GetNotificationCountForTest() const;
-  bool HasNotificationForTest(const std::string& id) const;
-  void RemoveAllNotificationsForTest();
-  size_t GetMessageCenterNotificationCountForTest() const;
-  size_t GetPopupNotificationCountForTest() const;
-
   message_center::WebNotificationList* notification_list() {
     return notification_list_.get();
   }
-  message_center::MessageCenterBubble* message_center_bubble() const {
+
+  internal::WebNotificationBubbleWrapper* message_center_bubble() const {
     return message_center_bubble_.get();
   }
-  message_center::PopupBubble* popup_bubble() const {
+
+  internal::WebNotificationBubbleWrapper* popup_bubble() const {
     return popup_bubble_.get();
   }
 
+  // Testing accessors.
+  message_center::MessageCenterBubble* GetMessageCenterBubbleForTest();
+  message_center::PopupBubble* GetPopupBubbleForTest();
+
   scoped_ptr<message_center::WebNotificationList> notification_list_;
-  scoped_ptr<message_center::MessageCenterBubble> message_center_bubble_;
-  scoped_ptr<message_center::PopupBubble> popup_bubble_;
+  scoped_ptr<internal::WebNotificationBubbleWrapper> message_center_bubble_;
+  scoped_ptr<internal::WebNotificationBubbleWrapper> popup_bubble_;
   views::ImageButton* button_;
   Delegate* delegate_;
   bool show_message_center_on_unlock_;
@@ -218,4 +211,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
+#endif  // ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index 0de2575..4867ca06 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -9,6 +9,9 @@
 #include "ash/root_window_controller.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray_item.h"
+#include "ash/system/web_notification/message_center_bubble.h"
+#include "ash/system/web_notification/popup_bubble.h"
+#include "ash/system/web_notification/web_notification_list.h"
 #include "ash/test/ash_test_base.h"
 #include "base/stringprintf.h"
 #include "base/utf_string_conversions.h"
@@ -96,31 +99,31 @@
 
   // Add a notification.
   delegate->AddNotification(tray, "test_id1");
-  EXPECT_EQ(1u, tray->GetNotificationCountForTest());
-  EXPECT_TRUE(tray->HasNotificationForTest("test_id1"));
+  EXPECT_EQ(1u, tray->notification_list()->notifications().size());
+  EXPECT_TRUE(tray->notification_list()->HasNotification("test_id1"));
   delegate->AddNotification(tray, "test_id2");
   delegate->AddNotification(tray, "test_id2");
-  EXPECT_EQ(2u, tray->GetNotificationCountForTest());
-  EXPECT_TRUE(tray->HasNotificationForTest("test_id2"));
+  EXPECT_EQ(2u, tray->notification_list()->notifications().size());
+  EXPECT_TRUE(tray->notification_list()->HasNotification("test_id2"));
 
   // Ensure that updating a notification does not affect the count.
   delegate->UpdateNotification(tray, "test_id2", "test_id3");
   delegate->UpdateNotification(tray, "test_id3", "test_id3");
-  EXPECT_EQ(2u, tray->GetNotificationCountForTest());
+  EXPECT_EQ(2u, tray->notification_list()->notifications().size());
   EXPECT_FALSE(delegate->HasNotificationId("test_id2"));
-  EXPECT_FALSE(tray->HasNotificationForTest("test_id2"));
+  EXPECT_FALSE(tray->notification_list()->HasNotification("test_id2"));
   EXPECT_TRUE(delegate->HasNotificationId("test_id3"));
 
   // Ensure that Removing the first notification removes it from the tray.
   delegate->RemoveNotification(tray, "test_id1");
   EXPECT_FALSE(delegate->HasNotificationId("test_id1"));
-  EXPECT_FALSE(tray->HasNotificationForTest("test_id1"));
-  EXPECT_EQ(1u, tray->GetNotificationCountForTest());
+  EXPECT_FALSE(tray->notification_list()->HasNotification("test_id1"));
+  EXPECT_EQ(1u, tray->notification_list()->notifications().size());
 
   // Remove the remianing notification.
   delegate->RemoveNotification(tray, "test_id3");
-  EXPECT_EQ(0u, tray->GetNotificationCountForTest());
-  EXPECT_FALSE(tray->HasNotificationForTest("test_id3"));
+  EXPECT_EQ(0u, tray->notification_list()->notifications().size());
+  EXPECT_FALSE(tray->notification_list()->HasNotification("test_id3"));
 }
 
 TEST_F(WebNotificationTrayTest, WebNotificationPopupBubble) {
@@ -148,6 +151,8 @@
   EXPECT_TRUE(tray->popup_bubble() == NULL);
 }
 
+using message_center::WebNotificationList;
+
 TEST_F(WebNotificationTrayTest, ManyMessageCenterNotifications) {
   WebNotificationTray* tray = GetWebNotificationTray();
   scoped_ptr<TestDelegate> delegate(new TestDelegate);
@@ -155,7 +160,7 @@
 
   // Add the max visible notifications +1, ensure the correct visible number.
   size_t notifications_to_add =
-      WebNotificationTray::kMaxVisibleTrayNotifications + 1;
+      WebNotificationList::kMaxVisibleMessageCenterNotifications + 1;
   for (size_t i = 0; i < notifications_to_add; ++i) {
     std::string id = StringPrintf("test_id%d", static_cast<int>(i));
     delegate->AddNotification(tray, id);
@@ -163,9 +168,10 @@
   tray->ShowMessageCenterBubble();
   RunAllPendingInMessageLoop();
   EXPECT_TRUE(tray->message_center_bubble() != NULL);
-  EXPECT_EQ(notifications_to_add, tray->GetNotificationCountForTest());
-  EXPECT_EQ(WebNotificationTray::kMaxVisibleTrayNotifications,
-            tray->GetMessageCenterNotificationCountForTest());
+  EXPECT_EQ(notifications_to_add,
+            tray->notification_list()->notifications().size());
+  EXPECT_EQ(WebNotificationList::kMaxVisibleMessageCenterNotifications,
+            tray->GetMessageCenterBubbleForTest()->NumMessageViewsForTest());
 }
 
 TEST_F(WebNotificationTrayTest, ManyPopupNotifications) {
@@ -175,7 +181,7 @@
 
   // Add the max visible popup notifications +1, ensure the correct num visible.
   size_t notifications_to_add =
-      WebNotificationTray::kMaxVisiblePopupNotifications + 1;
+      WebNotificationList::kMaxVisiblePopupNotifications + 1;
   for (size_t i = 0; i < notifications_to_add; ++i) {
     std::string id = StringPrintf("test_id%d", static_cast<int>(i));
     delegate->AddNotification(tray, id);
@@ -184,9 +190,10 @@
   tray->HidePopupBubble();
   tray->ShowPopupBubble();
   EXPECT_TRUE(tray->popup_bubble() != NULL);
-  EXPECT_EQ(notifications_to_add, tray->GetNotificationCountForTest());
-  EXPECT_EQ(WebNotificationTray::kMaxVisiblePopupNotifications,
-            tray->GetPopupNotificationCountForTest());
+  EXPECT_EQ(notifications_to_add,
+            tray->notification_list()->notifications().size());
+  EXPECT_EQ(WebNotificationList::kMaxVisiblePopupNotifications,
+            tray->GetPopupBubbleForTest()->NumMessageViewsForTest());
 }
 
 }  // namespace ash
diff --git a/ash/system/web_notification/web_notification_view.cc b/ash/system/web_notification/web_notification_view.cc
index faa3714..4abae743 100644
--- a/ash/system/web_notification/web_notification_view.cc
+++ b/ash/system/web_notification/web_notification_view.cc
@@ -4,23 +4,25 @@
 
 #include "ash/system/web_notification/web_notification_view.h"
 
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/tray/tray_views.h"
-#include "ash/system/web_notification/web_notification.h"
-#include "ash/system/web_notification/web_notification_tray.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/menu/menu_model_adapter.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/widget/widget.h"
 
-namespace ash {
+namespace {
+const int kPaddingHorizontal = 18;
+const int kPaddingBetweenItems = 10;
+}
 
 namespace message_center {
 
@@ -36,10 +38,10 @@
 class WebNotificationMenuModel : public ui::SimpleMenuModel,
                                  public ui::SimpleMenuModel::Delegate {
  public:
-  explicit WebNotificationMenuModel(WebNotificationTray* tray,
-                                    const WebNotification& notification)
+  WebNotificationMenuModel(WebNotificationList::Delegate* list_delegate,
+                           const WebNotification& notification)
       : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)),
-        tray_(tray),
+        list_delegate_(list_delegate),
         notification_(notification) {
     // Add 'disable notifications' menu item.
     if (!notification.extension_id.empty()) {
@@ -96,13 +98,13 @@
   virtual void ExecuteCommand(int command_id) OVERRIDE {
     switch (command_id) {
       case kToggleExtensionCommand:
-        tray_->DisableByExtension(notification_.id);
+        list_delegate_->DisableNotificationByExtension(notification_.id);
         break;
       case kTogglePermissionCommand:
-        tray_->DisableByUrl(notification_.id);
+        list_delegate_->DisableNotificationByUrl(notification_.id);
         break;
       case kShowSettingsCommand:
-        tray_->ShowSettings(notification_.id);
+        list_delegate_->ShowNotificationSettings(notification_.id);
         break;
       default:
         NOTREACHED();
@@ -110,16 +112,17 @@
   }
 
  private:
-  WebNotificationTray* tray_;
+  WebNotificationList::Delegate* list_delegate_;
   WebNotification notification_;
 
   DISALLOW_COPY_AND_ASSIGN(WebNotificationMenuModel);
 };
 
-WebNotificationView::WebNotificationView(WebNotificationTray* tray,
-                                         const WebNotification& notification,
-                                         int scroll_bar_width)
-    : tray_(tray),
+WebNotificationView::WebNotificationView(
+    WebNotificationList::Delegate* list_delegate,
+    const WebNotification& notification,
+    int scroll_bar_width)
+    : list_delegate_(list_delegate),
       notification_(notification),
       icon_(NULL),
       close_button_(NULL),
@@ -156,7 +159,7 @@
 
   views::ColumnSet* columns = layout->AddColumnSet(0);
 
-  const int padding_width = kTrayPopupPaddingHorizontal/2;
+  const int padding_width = kPaddingHorizontal / 2;
   columns->AddPaddingColumn(0, padding_width);
 
   // Notification Icon.
@@ -185,7 +188,7 @@
                      kWebNotificationButtonWidth);
 
   // Layout rows
-  layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems);
+  layout->AddPaddingRow(0, kPaddingBetweenItems);
 
   layout->StartRow(0, 0);
   layout->AddView(icon_, 1, 2);
@@ -195,7 +198,7 @@
   layout->StartRow(0, 0);
   layout->SkipColumns(2);
   layout->AddView(message, 1, 1);
-  layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems);
+  layout->AddPaddingRow(0, kPaddingBetweenItems);
 }
 
 WebNotificationView::~WebNotificationView() {
@@ -206,14 +209,14 @@
     ShowMenu(event.location());
     return true;
   }
-  tray_->OnClicked(notification_.id);
+  list_delegate_->OnNotificationClicked(notification_.id);
   return true;
 }
 
 ui::EventResult WebNotificationView::OnGestureEvent(
     const ui::GestureEvent& event) {
   if (event.type() == ui::ET_GESTURE_TAP) {
-    tray_->OnClicked(notification_.id);
+    list_delegate_->OnNotificationClicked(notification_.id);
     return ui::ER_CONSUMED;
   }
 
@@ -268,15 +271,15 @@
 void WebNotificationView::ButtonPressed(views::Button* sender,
                                         const ui::Event& event) {
   if (sender == close_button_)
-    tray_->SendRemoveNotification(notification_.id);
+    list_delegate_->SendRemoveNotification(notification_.id);
 }
 
 void WebNotificationView::OnImplicitAnimationsCompleted() {
-  tray_->SendRemoveNotification(notification_.id);
+  list_delegate_->SendRemoveNotification(notification_.id);
 }
 
 void WebNotificationView::ShowMenu(gfx::Point screen_location) {
-  WebNotificationMenuModel menu_model(tray_, notification_);
+  WebNotificationMenuModel menu_model(list_delegate_, notification_);
   if (menu_model.GetItemCount() == 0)
     return;
 
@@ -317,5 +320,3 @@
 }
 
 }  // namespace message_center
-
-}  // namespace ash
diff --git a/ash/system/web_notification/web_notification_view.h b/ash/system/web_notification/web_notification_view.h
index 688738c..2606166 100644
--- a/ash/system/web_notification/web_notification_view.h
+++ b/ash/system/web_notification/web_notification_view.h
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_VIEW_H_
-#define ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_VIEW_H_
+#ifndef ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_VIEW_H_
+#define ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_VIEW_H_
 
 #include "ash/system/web_notification/web_notification.h"
+#include "ash/system/web_notification/web_notification_list.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
@@ -16,10 +17,6 @@
 class ScrollView;
 }
 
-namespace ash {
-
-class WebNotificationTray;
-
 namespace message_center {
 
 // Individual notifications constants
@@ -32,7 +29,7 @@
                             public views::ButtonListener,
                             public ui::ImplicitAnimationObserver {
  public:
-  WebNotificationView(WebNotificationTray* tray,
+  WebNotificationView(WebNotificationList::Delegate* list_delegate,
                       const WebNotification& notification,
                       int scroll_bar_width);
 
@@ -68,7 +65,7 @@
   // Slides the view out and closes it after the animation.
   void SlideOutAndClose(SlideDirection direction);
 
-  WebNotificationTray* tray_;
+  WebNotificationList::Delegate* list_delegate_;
   WebNotification notification_;
   views::ImageView* icon_;
   views::ImageButton* close_button_;
@@ -81,6 +78,4 @@
 
 }  // namespace message_center
 
-}  // namespace ash
-
-#endif // ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_VIEW_H_
+#endif // ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_VIEW_H_