summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-09 22:37:24 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-09 22:37:24 +0000
commitb26aefbd6f804b74130bbec03952b72dac182a7a (patch)
tree7867ce4e7870c8a116247c98c13e16e531622949 /ash
parent06305964e02af11bda4699175340ffec2f784f6b (diff)
downloadchromium_src-b26aefbd6f804b74130bbec03952b72dac182a7a.zip
chromium_src-b26aefbd6f804b74130bbec03952b72dac182a7a.tar.gz
chromium_src-b26aefbd6f804b74130bbec03952b72dac182a7a.tar.bz2
ash: Separate out SystemTrayBubble and related classes into a new file.
BUG=none TEST=none Review URL: https://chromiumcodereview.appspot.com/10378070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@136156 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/system/tray/system_tray.cc592
-rw-r--r--ash/system/tray/system_tray_bubble.cc525
-rw-r--r--ash/system/tray/system_tray_bubble.h122
-rw-r--r--ash/system/tray/tray_constants.cc3
-rw-r--r--ash/system/tray/tray_constants.h3
6 files changed, 656 insertions, 591 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 9b53f00..19563d4 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -140,6 +140,8 @@
'system/settings/tray_settings.h',
'system/tray/system_tray.cc',
'system/tray/system_tray.h',
+ 'system/tray/system_tray_bubble.cc',
+ 'system/tray/system_tray_bubble.h',
'system/tray/system_tray_delegate.cc',
'system/tray/system_tray_delegate.h',
'system/tray/system_tray_item.cc',
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index ae1e44c..5342f9c 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -18,6 +18,7 @@
#include "ash/system/power/power_supply_status.h"
#include "ash/system/power/tray_power.h"
#include "ash/system/settings/tray_settings.h"
+#include "ash/system/tray/system_tray_bubble.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_item.h"
#include "ash/system/tray/system_tray_widget_delegate.h"
@@ -28,33 +29,20 @@
#include "ash/system/tray_update.h"
#include "ash/system/user/login_status.h"
#include "ash/system/user/tray_user.h"
-#include "ash/wm/shadow_types.h"
#include "ash/wm/shelf_layout_manager.h"
-#include "ash/wm/window_animations.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/message_pump_observer.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
#include "grit/ash_strings.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
#include "ui/aura/root_window.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/events.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/border.h"
-#include "ui/views/bubble/bubble_border.h"
-#include "ui/views/bubble/bubble_delegate.h"
-#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
@@ -65,234 +53,9 @@ namespace ash {
namespace {
-const int kPaddingFromRightEdgeOfScreen = 15;
-const int kPaddingFromBottomOfScreen = 10;
-
-const int kAnimationDurationForPopupMS = 200;
-
-const int kArrowHeight = 10;
-const int kArrowWidth = 20;
-const int kArrowPaddingFromRight = 20;
-
-const int kShadowThickness = 4;
-
-const int kLeftPadding = 4;
-const int kBottomLineHeight = 1;
-
-const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0);
-
const SkColor kTrayBackgroundAlpha = 100;
const SkColor kTrayBackgroundHoverAlpha = 150;
-void DrawBlurredShadowAroundView(gfx::Canvas* canvas,
- int top,
- int bottom,
- int width,
- const gfx::Insets& inset) {
- SkPath path;
- path.incReserve(4);
- path.moveTo(SkIntToScalar(inset.left() + kShadowThickness),
- SkIntToScalar(top + kShadowThickness + 1));
- path.lineTo(SkIntToScalar(inset.left() + kShadowThickness),
- SkIntToScalar(bottom));
- path.lineTo(SkIntToScalar(width),
- SkIntToScalar(bottom));
- path.lineTo(SkIntToScalar(width),
- SkIntToScalar(top + kShadowThickness + 1));
-
- SkPaint paint;
- paint.setColor(kShadowColor);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
- paint.setStrokeWidth(SkIntToScalar(3));
- paint.setImageFilter(new SkBlurImageFilter(
- SkIntToScalar(3), SkIntToScalar(3)))->unref();
- canvas->sk_canvas()->drawPath(path, paint);
-}
-
-// A view with some special behaviour for tray items in the popup:
-// - changes background color on hover.
-class TrayPopupItemContainer : public views::View {
- public:
- explicit TrayPopupItemContainer(views::View* view) : hover_(false) {
- set_notify_enter_exit_on_child(true);
- set_border(view->border() ? views::Border::CreateEmptyBorder(0, 0, 0, 0) :
- NULL);
- SetLayoutManager(new views::FillLayout);
- SetPaintToLayer(view->layer() != NULL);
- if (view->layer())
- SetFillsBoundsOpaquely(view->layer()->fills_bounds_opaquely());
- AddChildView(view);
- SetVisible(view->visible());
- }
-
- virtual ~TrayPopupItemContainer() {}
-
- private:
- // Overridden from views::View.
- virtual void ChildVisibilityChanged(View* child) OVERRIDE {
- if (visible() == child->visible())
- return;
- SetVisible(child->visible());
- PreferredSizeChanged();
- }
-
- virtual void ChildPreferredSizeChanged(View* child) OVERRIDE {
- PreferredSizeChanged();
- }
-
- virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE {
- hover_ = true;
- SchedulePaint();
- }
-
- virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE {
- hover_ = false;
- SchedulePaint();
- }
-
- virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE {
- if (child_count() == 0)
- return;
-
- views::View* view = child_at(0);
- if (!view->background()) {
- canvas->FillRect(gfx::Rect(size()),
- hover_ ? kHoverBackgroundColor : kBackgroundColor);
- }
- }
-
- bool hover_;
-
- DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer);
-};
-
-class SystemTrayBubbleBackground : public views::Background {
- public:
- explicit SystemTrayBubbleBackground(views::View* owner)
- : owner_(owner) {
- }
-
- virtual ~SystemTrayBubbleBackground() {}
-
- private:
- // Overridden from views::Background.
- virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
- views::View* last_view = NULL;
- for (int i = 0; i < owner_->child_count(); i++) {
- views::View* v = owner_->child_at(i);
-
- if (!v->border()) {
- canvas->DrawLine(gfx::Point(v->x(), v->y() - 1),
- gfx::Point(v->x() + v->width(), v->y() - 1),
- !last_view || last_view->border() ? kBorderDarkColor :
- kBorderLightColor);
- canvas->DrawLine(gfx::Point(v->x() - 1, v->y() - 1),
- gfx::Point(v->x() - 1, v->y() + v->height() + 1),
- kBorderDarkColor);
- canvas->DrawLine(gfx::Point(v->x() + v->width(), v->y() - 1),
- gfx::Point(v->x() + v->width(), v->y() + v->height() + 1),
- kBorderDarkColor);
- } else if (last_view && !last_view->border()) {
- canvas->DrawLine(gfx::Point(v->x() - 1, v->y() - 1),
- gfx::Point(v->x() + v->width() + 1, v->y() - 1),
- kBorderDarkColor);
- }
-
- last_view = v;
- }
- }
-
- views::View* owner_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBackground);
-};
-
-class SystemTrayBubbleBorder : public views::BubbleBorder {
- public:
- enum ArrowType {
- ARROW_TYPE_NONE,
- ARROW_TYPE_BOTTOM,
- };
-
- SystemTrayBubbleBorder(views::View* owner, ArrowType arrow_type)
- : views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT,
- views::BubbleBorder::NO_SHADOW),
- owner_(owner),
- arrow_type_(arrow_type) {
- set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
- }
-
- virtual ~SystemTrayBubbleBorder() {}
-
- private:
- // Overridden from views::Border.
- virtual void Paint(const views::View& view,
- gfx::Canvas* canvas) const OVERRIDE {
- views::View* first = NULL, *last = NULL;
- gfx::Insets inset;
- GetInsets(&inset);
- for (int i = 0; i < owner_->child_count(); i++) {
- views::View* v = owner_->child_at(i);
- if (v->border()) {
- if (first) {
- DrawBlurredShadowAroundView(canvas, first->y(),
- last->y() + last->height(), owner_->width(), inset);
- first = NULL;
- last = NULL;
- }
- continue;
- }
-
- if (!first)
- first = v;
- last = v;
- }
- if (first) {
- DrawBlurredShadowAroundView(canvas, first->y(),
- last->y() + last->height(), owner_->width(), inset);
- }
-
- // Draw the bottom line.
- int y = owner_->height() + 1;
- canvas->FillRect(gfx::Rect(kLeftPadding, y, owner_->width(),
- kBottomLineHeight), kBorderDarkColor);
-
- if (!Shell::GetInstance()->shelf()->IsVisible())
- return;
-
- // Draw the arrow.
- if (arrow_type_ == ARROW_TYPE_BOTTOM) {
- int left_base_x = base::i18n::IsRTL() ? kArrowWidth :
- owner_->width() - kArrowPaddingFromRight - kArrowWidth;
- int left_base_y = y;
- int tip_x = left_base_x + kArrowWidth / 2;
- int tip_y = left_base_y + kArrowHeight;
- SkPath path;
- path.incReserve(4);
- path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y));
- path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
- path.lineTo(SkIntToScalar(left_base_x + kArrowWidth),
- SkIntToScalar(left_base_y));
-
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(kBackgroundColor);
- canvas->DrawPath(path, paint);
-
- // Now draw the arrow border.
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(kBorderDarkColor);
- canvas->DrawPath(path, paint);
- }
- }
-
- views::View* owner_;
- ArrowType arrow_type_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBorder);
-};
-
} // namespace
namespace internal {
@@ -323,359 +86,6 @@ class SystemTrayBackground : public views::Background {
DISALLOW_COPY_AND_ASSIGN(SystemTrayBackground);
};
-class SystemTrayBubble;
-
-class SystemTrayBubbleView : public views::BubbleDelegateView {
- public:
- SystemTrayBubbleView(views::View* anchor,
- SystemTrayBubble* host,
- bool can_activate);
- virtual ~SystemTrayBubbleView();
-
- void SetBubbleBorder(views::BubbleBorder* border) {
- GetBubbleFrameView()->SetBubbleBorder(border);
- }
-
- void UpdateAnchor() {
- SizeToContents();
- GetWidget()->GetRootView()->SchedulePaint();
- }
-
- // Called when the host is destroyed.
- void reset_host() { host_ = NULL; }
-
- private:
- // Overridden from views::BubbleDelegateView.
- virtual void Init() OVERRIDE;
- virtual gfx::Rect GetAnchorRect() OVERRIDE;
- // Overridden from views::View.
- virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
- virtual bool CanActivate() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE;
- virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
-
- SystemTrayBubble* host_;
- bool can_activate_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleView);
-};
-
-class SystemTrayBubble : public base::MessagePumpObserver,
- public views::Widget::Observer {
- public:
- enum BubbleType {
- BUBBLE_TYPE_DEFAULT,
- BUBBLE_TYPE_DETAILED,
- BUBBLE_TYPE_NOTIFICATION
- };
-
- enum AnchorType {
- ANCHOR_TYPE_TRAY,
- ANCHOR_TYPE_BUBBLE
- };
-
- SystemTrayBubble(ash::SystemTray* tray,
- const std::vector<ash::SystemTrayItem*>& items,
- BubbleType bubble_type);
- virtual ~SystemTrayBubble();
-
- // Creates |bubble_view_| and a child views for each member of |items_|.
- // Also creates |bubble_widget_| and sets up animations.
- void InitView(views::View* anchor,
- AnchorType anchor_type,
- bool can_activate,
- ash::user::LoginStatus login_status);
-
- gfx::Rect GetAnchorRect() const;
-
- BubbleType bubble_type() const { return bubble_type_; }
- SystemTrayBubbleView* bubble_view() const { return bubble_view_; }
-
- void DestroyItemViews();
- void StartAutoCloseTimer(int seconds);
- void StopAutoCloseTimer();
- void RestartAutoCloseTimer();
- void Close();
-
- private:
- // Overridden from base::MessagePumpObserver.
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE;
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
- // Overridden from views::Widget::Observer.
- virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
- virtual void OnWidgetVisibilityChanged(views::Widget* widget,
- bool visible) OVERRIDE;
-
- ash::SystemTray* tray_;
- SystemTrayBubbleView* bubble_view_;
- views::Widget* bubble_widget_;
- std::vector<ash::SystemTrayItem*> items_;
- BubbleType bubble_type_;
- AnchorType anchor_type_;
-
- int autoclose_delay_;
- base::OneShotTimer<SystemTrayBubble> autoclose_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble);
-};
-
-// SystemTrayBubbleView
-
-SystemTrayBubbleView::SystemTrayBubbleView(views::View* anchor,
- SystemTrayBubble* host,
- bool can_activate)
- : views::BubbleDelegateView(anchor, views::BubbleBorder::BOTTOM_RIGHT),
- host_(host),
- can_activate_(can_activate) {
- set_margin(0);
- set_parent_window(ash::Shell::GetInstance()->GetContainer(
- ash::internal::kShellWindowId_SettingBubbleContainer));
- set_notify_enter_exit_on_child(true);
-}
-
-SystemTrayBubbleView::~SystemTrayBubbleView() {
- // Inform host items (models) that their views are being destroyed.
- if (host_)
- host_->DestroyItemViews();
-}
-
-void SystemTrayBubbleView::Init() {
- SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 1, 1, 1));
- set_background(new SystemTrayBubbleBackground(this));
-}
-
-gfx::Rect SystemTrayBubbleView::GetAnchorRect() {
- gfx::Rect rect;
- if (host_)
- rect = host_->GetAnchorRect();
- if (rect.IsEmpty()) {
- rect = gfx::Screen::GetPrimaryMonitor().bounds();
- rect = gfx::Rect(base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen :
- rect.width() - kPaddingFromRightEdgeOfScreen,
- rect.height() - kPaddingFromBottomOfScreen,
- 0, 0);
- }
- return rect;
-}
-
-void SystemTrayBubbleView::ChildPreferredSizeChanged(View* child) {
- SizeToContents();
-}
-
-void SystemTrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) {
- if (can_activate_) {
- state->role = ui::AccessibilityTypes::ROLE_WINDOW;
- state->name = l10n_util::GetStringUTF16(
- IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
- }
-}
-
-bool SystemTrayBubbleView::CanActivate() const {
- return can_activate_;
-}
-
-gfx::Size SystemTrayBubbleView::GetPreferredSize() {
- gfx::Size size = views::BubbleDelegateView::GetPreferredSize();
- return gfx::Size(kTrayPopupWidth, size.height());
-}
-
-void SystemTrayBubbleView::OnMouseEntered(const views::MouseEvent& event) {
- if (host_)
- host_->StopAutoCloseTimer();
-}
-
-void SystemTrayBubbleView::OnMouseExited(const views::MouseEvent& event) {
- if (host_)
- host_->RestartAutoCloseTimer();
-}
-
-// SystemTrayBubble
-
-SystemTrayBubble::SystemTrayBubble(
- ash::SystemTray* tray,
- const std::vector<ash::SystemTrayItem*>& items,
- BubbleType bubble_type)
- : tray_(tray),
- bubble_view_(NULL),
- bubble_widget_(NULL),
- items_(items),
- bubble_type_(bubble_type),
- anchor_type_(ANCHOR_TYPE_TRAY),
- autoclose_delay_(0) {
-}
-
-SystemTrayBubble::~SystemTrayBubble() {
- // The bubble may be closing without having been hidden first. So it may still
- // be in the message-loop's observer list.
- MessageLoopForUI::current()->RemoveObserver(this);
-
- DestroyItemViews();
- // Reset the host pointer in bubble_view_ in case its destruction is deferred.
- if (bubble_view_)
- bubble_view_->reset_host();
- if (bubble_widget_) {
- bubble_widget_->RemoveObserver(this);
- // This triggers the destruction of bubble_view_.
- bubble_widget_->Close();
- }
-}
-
-void SystemTrayBubble::InitView(views::View* anchor,
- AnchorType anchor_type,
- bool can_activate,
- ash::user::LoginStatus login_status) {
- DCHECK(bubble_view_ == NULL);
- anchor_type_ = anchor_type;
- bubble_view_ = new SystemTrayBubbleView(anchor, this, can_activate);
-
- for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
- it != items_.end();
- ++it) {
- views::View* view = NULL;
- switch (bubble_type_) {
- case BUBBLE_TYPE_DEFAULT:
- view = (*it)->CreateDefaultView(login_status);
- break;
- case BUBBLE_TYPE_DETAILED:
- view = (*it)->CreateDetailedView(login_status);
- break;
- case BUBBLE_TYPE_NOTIFICATION:
- view = (*it)->CreateNotificationView(login_status);
- break;
- }
- if (view)
- bubble_view_->AddChildView(new TrayPopupItemContainer(view));
- }
-
- DCHECK(bubble_widget_ == NULL);
- bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_);
-
- // Must occur after call to CreateBubble()
- bubble_view_->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
- bubble_widget_->non_client_view()->frame_view()->set_background(NULL);
- SystemTrayBubbleBorder::ArrowType arrow_type;
- if (anchor_type_ == ANCHOR_TYPE_TRAY)
- arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_BOTTOM;
- else
- arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_NONE;
- bubble_view_->SetBubbleBorder(
- new SystemTrayBubbleBorder(bubble_view_, arrow_type));
-
- bubble_widget_->AddObserver(this);
-
- // Setup animation.
- ash::SetWindowVisibilityAnimationType(
- bubble_widget_->GetNativeWindow(),
- ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
- ash::SetWindowVisibilityAnimationTransition(
- bubble_widget_->GetNativeWindow(),
- ash::ANIMATE_BOTH);
- ash::SetWindowVisibilityAnimationDuration(
- bubble_widget_->GetNativeWindow(),
- base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
-
- bubble_view_->Show();
-}
-
-gfx::Rect SystemTrayBubble::GetAnchorRect() const {
- gfx::Rect rect;
- views::Widget* widget = bubble_view()->anchor_widget();
- if (widget->IsVisible()) {
- rect = widget->GetWindowScreenBounds();
- if (anchor_type_ == ANCHOR_TYPE_TRAY) {
- rect.Inset(
- base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : 0,
- 0,
- base::i18n::IsRTL() ? 0 : kPaddingFromRightEdgeOfScreen,
- kPaddingFromBottomOfScreen);
- } else if (anchor_type_ == ANCHOR_TYPE_BUBBLE) {
- rect.Inset(
- base::i18n::IsRTL() ? kShadowThickness - 1 : 0,
- 0,
- base::i18n::IsRTL() ? 0 : kShadowThickness - 1,
- 0);
- }
- }
- return rect;
-}
-
-void SystemTrayBubble::DestroyItemViews() {
- for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
- it != items_.end();
- ++it) {
- switch (bubble_type_) {
- case BUBBLE_TYPE_DEFAULT:
- (*it)->DestroyDefaultView();
- break;
- case BUBBLE_TYPE_DETAILED:
- (*it)->DestroyDetailedView();
- break;
- case BUBBLE_TYPE_NOTIFICATION:
- (*it)->DestroyNotificationView();
- break;
- }
- }
-}
-
-void SystemTrayBubble::StartAutoCloseTimer(int seconds) {
- autoclose_.Stop();
- autoclose_delay_ = seconds;
- if (autoclose_delay_) {
- autoclose_.Start(FROM_HERE,
- base::TimeDelta::FromSeconds(autoclose_delay_),
- this, &SystemTrayBubble::Close);
- }
-}
-
-void SystemTrayBubble::StopAutoCloseTimer() {
- autoclose_.Stop();
-}
-
-void SystemTrayBubble::RestartAutoCloseTimer() {
- if (autoclose_delay_)
- StartAutoCloseTimer(autoclose_delay_);
-}
-
-void SystemTrayBubble::Close() {
- if (bubble_widget_)
- bubble_widget_->Close();
-}
-
-base::EventStatus SystemTrayBubble::WillProcessEvent(
- const base::NativeEvent& event) {
- // Check if the user clicked outside of the bubble and close it if they did.
- if (bubble_type_ != BUBBLE_TYPE_NOTIFICATION &&
- ui::EventTypeFromNative(event) == ui::ET_MOUSE_PRESSED) {
- gfx::Point cursor_in_view = ui::EventLocationFromNative(event);
- views::View::ConvertPointFromScreen(bubble_view_, &cursor_in_view);
- if (!bubble_view_->HitTest(cursor_in_view)) {
- bubble_widget_->Close();
- }
- }
- return base::EVENT_CONTINUE;
-}
-
-void SystemTrayBubble::DidProcessEvent(const base::NativeEvent& event) {
-}
-
-void SystemTrayBubble::OnWidgetClosing(views::Widget* widget) {
- CHECK_EQ(bubble_widget_, widget);
- MessageLoopForUI::current()->RemoveObserver(this);
- bubble_widget_ = NULL;
- tray_->RemoveBubble(this);
-}
-
-void SystemTrayBubble::OnWidgetVisibilityChanged(views::Widget* widget,
- bool visible) {
- if (!visible)
- MessageLoopForUI::current()->RemoveObserver(this);
- else
- MessageLoopForUI::current()->AddObserver(this);
-}
-
// Observe the tray layer animation and update the anchor when it changes.
// TODO(stevenjb): Observe or mirror the actual animation, not just the start
// and end points.
diff --git a/ash/system/tray/system_tray_bubble.cc b/ash/system/tray/system_tray_bubble.cc
new file mode 100644
index 0000000..8a7810f
--- /dev/null
+++ b/ash/system/tray/system_tray_bubble.cc
@@ -0,0 +1,525 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/tray/system_tray_bubble.h"
+
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_item.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ash/wm/shelf_layout_manager.h"
+#include "ash/wm/window_animations.h"
+#include "base/message_loop.h"
+#include "grit/ash_strings.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/effects/SkBlurImageFilter.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view.h"
+
+namespace ash {
+
+namespace {
+
+const int kShadowThickness = 4;
+
+const int kLeftPadding = 4;
+const int kBottomLineHeight = 1;
+
+const int kArrowHeight = 10;
+const int kArrowWidth = 20;
+const int kArrowPaddingFromRight = 20;
+
+const int kAnimationDurationForPopupMS = 200;
+
+const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0);
+
+void DrawBlurredShadowAroundView(gfx::Canvas* canvas,
+ int top,
+ int bottom,
+ int width,
+ const gfx::Insets& inset) {
+ SkPath path;
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(inset.left() + kShadowThickness),
+ SkIntToScalar(top + kShadowThickness + 1));
+ path.lineTo(SkIntToScalar(inset.left() + kShadowThickness),
+ SkIntToScalar(bottom));
+ path.lineTo(SkIntToScalar(width),
+ SkIntToScalar(bottom));
+ path.lineTo(SkIntToScalar(width),
+ SkIntToScalar(top + kShadowThickness + 1));
+
+ SkPaint paint;
+ paint.setColor(kShadowColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ paint.setStrokeWidth(SkIntToScalar(3));
+ paint.setImageFilter(new SkBlurImageFilter(
+ SkIntToScalar(3), SkIntToScalar(3)))->unref();
+ canvas->sk_canvas()->drawPath(path, paint);
+}
+
+// A view with some special behaviour for tray items in the popup:
+// - changes background color on hover.
+class TrayPopupItemContainer : public views::View {
+ public:
+ explicit TrayPopupItemContainer(views::View* view) : hover_(false) {
+ set_notify_enter_exit_on_child(true);
+ set_border(view->border() ? views::Border::CreateEmptyBorder(0, 0, 0, 0) :
+ NULL);
+ SetLayoutManager(new views::FillLayout);
+ SetPaintToLayer(view->layer() != NULL);
+ if (view->layer())
+ SetFillsBoundsOpaquely(view->layer()->fills_bounds_opaquely());
+ AddChildView(view);
+ SetVisible(view->visible());
+ }
+
+ virtual ~TrayPopupItemContainer() {}
+
+ private:
+ // Overridden from views::View.
+ virtual void ChildVisibilityChanged(View* child) OVERRIDE {
+ if (visible() == child->visible())
+ return;
+ SetVisible(child->visible());
+ PreferredSizeChanged();
+ }
+
+ virtual void ChildPreferredSizeChanged(View* child) OVERRIDE {
+ PreferredSizeChanged();
+ }
+
+ virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE {
+ hover_ = true;
+ SchedulePaint();
+ }
+
+ virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE {
+ hover_ = false;
+ SchedulePaint();
+ }
+
+ virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE {
+ if (child_count() == 0)
+ return;
+
+ views::View* view = child_at(0);
+ if (!view->background()) {
+ canvas->FillRect(gfx::Rect(size()),
+ hover_ ? kHoverBackgroundColor : kBackgroundColor);
+ }
+ }
+
+ bool hover_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer);
+};
+
+class SystemTrayBubbleBackground : public views::Background {
+ public:
+ explicit SystemTrayBubbleBackground(views::View* owner)
+ : owner_(owner) {
+ }
+
+ virtual ~SystemTrayBubbleBackground() {}
+
+ private:
+ // Overridden from views::Background.
+ virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
+ views::View* last_view = NULL;
+ for (int i = 0; i < owner_->child_count(); i++) {
+ views::View* v = owner_->child_at(i);
+
+ if (!v->border()) {
+ canvas->DrawLine(gfx::Point(v->x(), v->y() - 1),
+ gfx::Point(v->x() + v->width(), v->y() - 1),
+ !last_view || last_view->border() ? kBorderDarkColor :
+ kBorderLightColor);
+ canvas->DrawLine(gfx::Point(v->x() - 1, v->y() - 1),
+ gfx::Point(v->x() - 1, v->y() + v->height() + 1),
+ kBorderDarkColor);
+ canvas->DrawLine(gfx::Point(v->x() + v->width(), v->y() - 1),
+ gfx::Point(v->x() + v->width(), v->y() + v->height() + 1),
+ kBorderDarkColor);
+ } else if (last_view && !last_view->border()) {
+ canvas->DrawLine(gfx::Point(v->x() - 1, v->y() - 1),
+ gfx::Point(v->x() + v->width() + 1, v->y() - 1),
+ kBorderDarkColor);
+ }
+
+ last_view = v;
+ }
+ }
+
+ views::View* owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBackground);
+};
+
+class SystemTrayBubbleBorder : public views::BubbleBorder {
+ public:
+ enum ArrowType {
+ ARROW_TYPE_NONE,
+ ARROW_TYPE_BOTTOM,
+ };
+
+ SystemTrayBubbleBorder(views::View* owner, ArrowType arrow_type)
+ : views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT,
+ views::BubbleBorder::NO_SHADOW),
+ owner_(owner),
+ arrow_type_(arrow_type) {
+ set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
+ }
+
+ virtual ~SystemTrayBubbleBorder() {}
+
+ private:
+ // Overridden from views::Border.
+ virtual void Paint(const views::View& view,
+ gfx::Canvas* canvas) const OVERRIDE {
+ views::View* first = NULL, *last = NULL;
+ gfx::Insets inset;
+ GetInsets(&inset);
+ for (int i = 0; i < owner_->child_count(); i++) {
+ views::View* v = owner_->child_at(i);
+ if (v->border()) {
+ if (first) {
+ DrawBlurredShadowAroundView(canvas, first->y(),
+ last->y() + last->height(), owner_->width(), inset);
+ first = NULL;
+ last = NULL;
+ }
+ continue;
+ }
+
+ if (!first)
+ first = v;
+ last = v;
+ }
+ if (first) {
+ DrawBlurredShadowAroundView(canvas, first->y(),
+ last->y() + last->height(), owner_->width(), inset);
+ }
+
+ // Draw the bottom line.
+ int y = owner_->height() + 1;
+ canvas->FillRect(gfx::Rect(kLeftPadding, y, owner_->width(),
+ kBottomLineHeight), kBorderDarkColor);
+
+ if (!Shell::GetInstance()->shelf()->IsVisible())
+ return;
+
+ // Draw the arrow.
+ if (arrow_type_ == ARROW_TYPE_BOTTOM) {
+ int left_base_x = base::i18n::IsRTL() ? kArrowWidth :
+ owner_->width() - kArrowPaddingFromRight - kArrowWidth;
+ int left_base_y = y;
+ int tip_x = left_base_x + kArrowWidth / 2;
+ int tip_y = left_base_y + kArrowHeight;
+ SkPath path;
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y));
+ path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
+ path.lineTo(SkIntToScalar(left_base_x + kArrowWidth),
+ SkIntToScalar(left_base_y));
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(kBackgroundColor);
+ canvas->DrawPath(path, paint);
+
+ // Now draw the arrow border.
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(kBorderDarkColor);
+ canvas->DrawPath(path, paint);
+ }
+ }
+
+ views::View* owner_;
+ ArrowType arrow_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBorder);
+};
+
+} // namespace
+
+namespace internal {
+
+// SystemTrayBubbleView
+
+SystemTrayBubbleView::SystemTrayBubbleView(views::View* anchor,
+ SystemTrayBubble* host,
+ bool can_activate)
+ : views::BubbleDelegateView(anchor, views::BubbleBorder::BOTTOM_RIGHT),
+ host_(host),
+ can_activate_(can_activate) {
+ set_margin(0);
+ set_parent_window(ash::Shell::GetInstance()->GetContainer(
+ ash::internal::kShellWindowId_SettingBubbleContainer));
+ set_notify_enter_exit_on_child(true);
+}
+
+SystemTrayBubbleView::~SystemTrayBubbleView() {
+ // Inform host items (models) that their views are being destroyed.
+ if (host_)
+ host_->DestroyItemViews();
+}
+
+void SystemTrayBubbleView::SetBubbleBorder(views::BubbleBorder* border) {
+ GetBubbleFrameView()->SetBubbleBorder(border);
+}
+
+void SystemTrayBubbleView::UpdateAnchor() {
+ SizeToContents();
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void SystemTrayBubbleView::Init() {
+ SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 1, 1, 1));
+ set_background(new SystemTrayBubbleBackground(this));
+}
+
+gfx::Rect SystemTrayBubbleView::GetAnchorRect() {
+ gfx::Rect rect;
+ if (host_)
+ rect = host_->GetAnchorRect();
+ if (rect.IsEmpty()) {
+ rect = gfx::Screen::GetPrimaryMonitor().bounds();
+ rect = gfx::Rect(base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen :
+ rect.width() - kPaddingFromRightEdgeOfScreen,
+ rect.height() - kPaddingFromBottomOfScreen,
+ 0, 0);
+ }
+ return rect;
+}
+
+void SystemTrayBubbleView::ChildPreferredSizeChanged(View* child) {
+ SizeToContents();
+}
+
+void SystemTrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) {
+ if (can_activate_) {
+ state->role = ui::AccessibilityTypes::ROLE_WINDOW;
+ state->name = l10n_util::GetStringUTF16(
+ IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
+ }
+}
+
+bool SystemTrayBubbleView::CanActivate() const {
+ return can_activate_;
+}
+
+gfx::Size SystemTrayBubbleView::GetPreferredSize() {
+ gfx::Size size = views::BubbleDelegateView::GetPreferredSize();
+ return gfx::Size(kTrayPopupWidth, size.height());
+}
+
+void SystemTrayBubbleView::OnMouseEntered(const views::MouseEvent& event) {
+ if (host_)
+ host_->StopAutoCloseTimer();
+}
+
+void SystemTrayBubbleView::OnMouseExited(const views::MouseEvent& event) {
+ if (host_)
+ host_->RestartAutoCloseTimer();
+}
+
+// SystemTrayBubble
+
+SystemTrayBubble::SystemTrayBubble(
+ ash::SystemTray* tray,
+ const std::vector<ash::SystemTrayItem*>& items,
+ BubbleType bubble_type)
+ : tray_(tray),
+ bubble_view_(NULL),
+ bubble_widget_(NULL),
+ items_(items),
+ bubble_type_(bubble_type),
+ anchor_type_(ANCHOR_TYPE_TRAY),
+ autoclose_delay_(0) {
+}
+
+SystemTrayBubble::~SystemTrayBubble() {
+ // The bubble may be closing without having been hidden first. So it may still
+ // be in the message-loop's observer list.
+ MessageLoopForUI::current()->RemoveObserver(this);
+
+ DestroyItemViews();
+ // Reset the host pointer in bubble_view_ in case its destruction is deferred.
+ if (bubble_view_)
+ bubble_view_->reset_host();
+ if (bubble_widget_) {
+ bubble_widget_->RemoveObserver(this);
+ // This triggers the destruction of bubble_view_.
+ bubble_widget_->Close();
+ }
+}
+
+void SystemTrayBubble::InitView(views::View* anchor,
+ AnchorType anchor_type,
+ bool can_activate,
+ ash::user::LoginStatus login_status) {
+ DCHECK(bubble_view_ == NULL);
+ anchor_type_ = anchor_type;
+ bubble_view_ = new SystemTrayBubbleView(anchor, this, can_activate);
+
+ for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
+ it != items_.end();
+ ++it) {
+ views::View* view = NULL;
+ switch (bubble_type_) {
+ case BUBBLE_TYPE_DEFAULT:
+ view = (*it)->CreateDefaultView(login_status);
+ break;
+ case BUBBLE_TYPE_DETAILED:
+ view = (*it)->CreateDetailedView(login_status);
+ break;
+ case BUBBLE_TYPE_NOTIFICATION:
+ view = (*it)->CreateNotificationView(login_status);
+ break;
+ }
+ if (view)
+ bubble_view_->AddChildView(new TrayPopupItemContainer(view));
+ }
+
+ DCHECK(bubble_widget_ == NULL);
+ bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_);
+
+ // Must occur after call to CreateBubble()
+ bubble_view_->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
+ bubble_widget_->non_client_view()->frame_view()->set_background(NULL);
+ SystemTrayBubbleBorder::ArrowType arrow_type;
+ if (anchor_type_ == ANCHOR_TYPE_TRAY)
+ arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_BOTTOM;
+ else
+ arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_NONE;
+ bubble_view_->SetBubbleBorder(
+ new SystemTrayBubbleBorder(bubble_view_, arrow_type));
+
+ bubble_widget_->AddObserver(this);
+
+ // Setup animation.
+ ash::SetWindowVisibilityAnimationType(
+ bubble_widget_->GetNativeWindow(),
+ ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
+ ash::SetWindowVisibilityAnimationTransition(
+ bubble_widget_->GetNativeWindow(),
+ ash::ANIMATE_BOTH);
+ ash::SetWindowVisibilityAnimationDuration(
+ bubble_widget_->GetNativeWindow(),
+ base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
+
+ bubble_view_->Show();
+}
+
+gfx::Rect SystemTrayBubble::GetAnchorRect() const {
+ gfx::Rect rect;
+ views::Widget* widget = bubble_view()->anchor_widget();
+ if (widget->IsVisible()) {
+ rect = widget->GetWindowScreenBounds();
+ if (anchor_type_ == ANCHOR_TYPE_TRAY) {
+ rect.Inset(
+ base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : 0,
+ 0,
+ base::i18n::IsRTL() ? 0 : kPaddingFromRightEdgeOfScreen,
+ kPaddingFromBottomOfScreen);
+ } else if (anchor_type_ == ANCHOR_TYPE_BUBBLE) {
+ rect.Inset(
+ base::i18n::IsRTL() ? kShadowThickness - 1 : 0,
+ 0,
+ base::i18n::IsRTL() ? 0 : kShadowThickness - 1,
+ 0);
+ }
+ }
+ return rect;
+}
+
+void SystemTrayBubble::DestroyItemViews() {
+ for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
+ it != items_.end();
+ ++it) {
+ switch (bubble_type_) {
+ case BUBBLE_TYPE_DEFAULT:
+ (*it)->DestroyDefaultView();
+ break;
+ case BUBBLE_TYPE_DETAILED:
+ (*it)->DestroyDetailedView();
+ break;
+ case BUBBLE_TYPE_NOTIFICATION:
+ (*it)->DestroyNotificationView();
+ break;
+ }
+ }
+}
+
+void SystemTrayBubble::StartAutoCloseTimer(int seconds) {
+ autoclose_.Stop();
+ autoclose_delay_ = seconds;
+ if (autoclose_delay_) {
+ autoclose_.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(autoclose_delay_),
+ this, &SystemTrayBubble::Close);
+ }
+}
+
+void SystemTrayBubble::StopAutoCloseTimer() {
+ autoclose_.Stop();
+}
+
+void SystemTrayBubble::RestartAutoCloseTimer() {
+ if (autoclose_delay_)
+ StartAutoCloseTimer(autoclose_delay_);
+}
+
+void SystemTrayBubble::Close() {
+ if (bubble_widget_)
+ bubble_widget_->Close();
+}
+
+base::EventStatus SystemTrayBubble::WillProcessEvent(
+ const base::NativeEvent& event) {
+ // Check if the user clicked outside of the bubble and close it if they did.
+ if (bubble_type_ != BUBBLE_TYPE_NOTIFICATION &&
+ ui::EventTypeFromNative(event) == ui::ET_MOUSE_PRESSED) {
+ gfx::Point cursor_in_view = ui::EventLocationFromNative(event);
+ views::View::ConvertPointFromScreen(bubble_view_, &cursor_in_view);
+ if (!bubble_view_->HitTest(cursor_in_view)) {
+ bubble_widget_->Close();
+ }
+ }
+ return base::EVENT_CONTINUE;
+}
+
+void SystemTrayBubble::DidProcessEvent(const base::NativeEvent& event) {
+}
+
+void SystemTrayBubble::OnWidgetClosing(views::Widget* widget) {
+ CHECK_EQ(bubble_widget_, widget);
+ MessageLoopForUI::current()->RemoveObserver(this);
+ bubble_widget_ = NULL;
+ tray_->RemoveBubble(this);
+}
+
+void SystemTrayBubble::OnWidgetVisibilityChanged(views::Widget* widget,
+ bool visible) {
+ if (!visible)
+ MessageLoopForUI::current()->RemoveObserver(this);
+ else
+ MessageLoopForUI::current()->AddObserver(this);
+}
+
+} // namespace internal
+} // namespace ash
diff --git a/ash/system/tray/system_tray_bubble.h b/ash/system/tray/system_tray_bubble.h
new file mode 100644
index 0000000..a29e748
--- /dev/null
+++ b/ash/system/tray/system_tray_bubble.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
+#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
+#pragma once
+
+#include "ash/system/user/login_status.h"
+#include "base/base_export.h"
+#include "base/message_pump_observer.h"
+#include "base/timer.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/widget/widget.h"
+
+#include <vector>
+
+namespace ash {
+
+class SystemTray;
+class SystemTrayItem;
+
+namespace internal {
+
+class SystemTrayBubble;
+
+class SystemTrayBubbleView : public views::BubbleDelegateView {
+ public:
+ SystemTrayBubbleView(views::View* anchor,
+ SystemTrayBubble* host,
+ bool can_activate);
+ virtual ~SystemTrayBubbleView();
+
+ void SetBubbleBorder(views::BubbleBorder* border);
+
+ void UpdateAnchor();
+
+ // Called when the host is destroyed.
+ void reset_host() { host_ = NULL; }
+
+ private:
+ // Overridden from views::BubbleDelegateView.
+ virtual void Init() OVERRIDE;
+ virtual gfx::Rect GetAnchorRect() OVERRIDE;
+ // Overridden from views::View.
+ virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual bool CanActivate() const OVERRIDE;
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
+
+ SystemTrayBubble* host_;
+ bool can_activate_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleView);
+};
+
+class SystemTrayBubble : public base::MessagePumpObserver,
+ public views::Widget::Observer {
+ public:
+ enum BubbleType {
+ BUBBLE_TYPE_DEFAULT,
+ BUBBLE_TYPE_DETAILED,
+ BUBBLE_TYPE_NOTIFICATION
+ };
+
+ enum AnchorType {
+ ANCHOR_TYPE_TRAY,
+ ANCHOR_TYPE_BUBBLE
+ };
+
+ SystemTrayBubble(ash::SystemTray* tray,
+ const std::vector<ash::SystemTrayItem*>& items,
+ BubbleType bubble_type);
+ virtual ~SystemTrayBubble();
+
+ // Creates |bubble_view_| and a child views for each member of |items_|.
+ // Also creates |bubble_widget_| and sets up animations.
+ void InitView(views::View* anchor,
+ AnchorType anchor_type,
+ bool can_activate,
+ ash::user::LoginStatus login_status);
+
+ gfx::Rect GetAnchorRect() const;
+
+ BubbleType bubble_type() const { return bubble_type_; }
+ SystemTrayBubbleView* bubble_view() const { return bubble_view_; }
+
+ void DestroyItemViews();
+ void StartAutoCloseTimer(int seconds);
+ void StopAutoCloseTimer();
+ void RestartAutoCloseTimer();
+ void Close();
+
+ private:
+ // Overridden from base::MessagePumpObserver.
+ virtual base::EventStatus WillProcessEvent(
+ const base::NativeEvent& event) OVERRIDE;
+ virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
+ // Overridden from views::Widget::Observer.
+ virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
+ virtual void OnWidgetVisibilityChanged(views::Widget* widget,
+ bool visible) OVERRIDE;
+
+ ash::SystemTray* tray_;
+ SystemTrayBubbleView* bubble_view_;
+ views::Widget* bubble_widget_;
+ std::vector<ash::SystemTrayItem*> items_;
+ BubbleType bubble_type_;
+ AnchorType anchor_type_;
+
+ int autoclose_delay_;
+ base::OneShotTimer<SystemTrayBubble> autoclose_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble);
+};
+
+} // namespace internal
+} // namespace ash
+
+#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc
index de787f9..d4427e9 100644
--- a/ash/system/tray/tray_constants.cc
+++ b/ash/system/tray/tray_constants.cc
@@ -8,6 +8,9 @@
namespace ash {
+const int kPaddingFromRightEdgeOfScreen = 15;
+const int kPaddingFromBottomOfScreen = 10;
+
const int kTrayPopupAutoCloseDelayInSeconds = 2;
const int kTrayPopupAutoCloseDelayForTextInSeconds = 5;
const int kTrayPopupPaddingHorizontal = 18;
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index b98ba57..7db11d6 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -10,6 +10,9 @@ typedef unsigned int SkColor;
namespace ash {
+extern const int kPaddingFromRightEdgeOfScreen;
+extern const int kPaddingFromBottomOfScreen;
+
extern const int kTrayPopupAutoCloseDelayInSeconds;
extern const int kTrayPopupAutoCloseDelayForTextInSeconds;
extern const int kTrayPopupPaddingHorizontal;