15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_bubble.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_item.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_bubble_wrapper.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_constants.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/message_loop/message_loop.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer_animation_observer.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/box_layout.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::TrayBubbleView;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Normally a detailed view is the same size as the default view. However,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when showing a detailed view directly (e.g. clicking on a notification),
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we may not know the height of the default view, or the default view may
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be too short, so we use this as a default and minimum height for any
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// detailed view.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDetailedBubbleMaxHeight = kTrayPopupItemHeight * 5;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Duration of swipe animation used when transitioning from a default to
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// detailed view or vice versa.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSwipeDelayMS = 150;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A view with some special behaviour for tray items in the popup:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - optionally changes background color on hover.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TrayPopupItemContainer : public views::View {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TrayPopupItemContainer(views::View* view,
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         bool change_background,
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         bool draw_border)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : hover_(false),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        change_background_(change_background) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_notify_enter_exit_on_child(true);
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (draw_border) {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SetBorder(
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          views::Border::CreateSolidSidedBorder(0, 0, 1, 0, kBorderLightColor));
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::BoxLayout* layout = new views::BoxLayout(
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        views::BoxLayout::kVertical, 0, 0, 0);
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    layout->SetDefaultFlex(1);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLayoutManager(layout);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetPaintToLayer(view->layer() != NULL);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (view->layer())
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetFillsBoundsOpaquely(view->layer()->fills_bounds_opaquely());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(view);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetVisible(view->visible());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~TrayPopupItemContainer() {}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overridden from views::View.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ChildVisibilityChanged(View* child) OVERRIDE {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visible() == child->visible())
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetVisible(child->visible());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PreferredSizeChanged();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PreferredSizeChanged();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hover_ = true;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SchedulePaint();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hover_ = false;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SchedulePaint();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (child_count() == 0)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = child_at(0);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!view->background()) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      canvas->FillRect(gfx::Rect(size()), (hover_ && change_background_) ?
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kHoverBackgroundColor : kBackgroundColor);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool hover_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool change_background_;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implicit animation observer that deletes itself and the layer at the end of
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the animation.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit AnimationObserverDeleteLayer(ui::Layer* layer)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : layer_(layer) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~AnimationObserverDeleteLayer() {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnImplicitAnimationsCompleted() OVERRIDE {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::MessageLoopForUI::current()->DeleteSoon(FROM_HERE, this);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ui::Layer> layer_;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AnimationObserverDeleteLayer);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SystemTrayBubble
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemTrayBubble::SystemTrayBubble(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ash::SystemTray* tray,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ash::SystemTrayItem*>& items,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BubbleType bubble_type)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : tray_(tray),
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bubble_view_(NULL),
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      items_(items),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bubble_type_(bubble_type),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      autoclose_delay_(0) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemTrayBubble::~SystemTrayBubble() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DestroyItemViews();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reset the host pointer in bubble_view_ in case its destruction is deferred.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bubble_view_)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bubble_view_->reset_delegate();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::UpdateView(
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ash::SystemTrayItem*>& items,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BubbleType bubble_type) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bubble_type != BUBBLE_TYPE_NOTIFICATION);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ui::Layer> scoped_layer;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bubble_type != bubble_type_) {
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta swipe_duration =
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(kSwipeDelayMS);
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_layer = bubble_view_->RecreateLayer();
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Keep the reference to layer as we need it after releasing it.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::Layer* layer = scoped_layer.get();
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(layer);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    layer->SuppressPaint();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // When transitioning from detailed view to default view, animate the
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // existing view (slide out towards the right).
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bubble_type == BUBBLE_TYPE_DEFAULT) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      settings.AddObserver(
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          new AnimationObserverDeleteLayer(scoped_layer.release()));
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      settings.SetTransitionDuration(swipe_duration);
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      settings.SetTweenType(gfx::Tween::EASE_OUT);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Transform transform;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      transform.Translate(layer->bounds().width(), 0.0);
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      layer->SetTransform(transform);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Add a shadow layer to make the old layer darker as the animation
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // progresses.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::Layer* shadow = new ui::Layer(ui::LAYER_SOLID_COLOR);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shadow->SetColor(SK_ColorBLACK);
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shadow->SetOpacity(0.01f);
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shadow->SetBounds(layer->bounds());
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      layer->Add(shadow);
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      layer->StackAtTop(shadow);
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Animate the darkening effect a little longer than the swipe-in. This
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // is to make sure the darkening animation does not end up finishing
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // early, because the dark layer goes away at the end of the animation,
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // and there is a brief moment when the old view is still visible, but
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // it does not have the shadow layer on top.
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ui::ScopedLayerAnimationSettings settings(shadow->GetAnimator());
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        settings.AddObserver(new AnimationObserverDeleteLayer(shadow));
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        settings.SetTransitionDuration(swipe_duration +
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::TimeDelta::FromMilliseconds(150));
197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        settings.SetTweenType(gfx::Tween::LINEAR);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        shadow->SetOpacity(0.15f);
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DestroyItemViews();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_view_->RemoveAllChildViews(true);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items_ = items;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_type_ = bubble_type;
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CreateItemViews(
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close bubble view if we failed to create the item view.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bubble_view_->has_children()) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Close();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_view_->GetWidget()->GetContentsView()->Layout();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure that the bubble is large enough for the default view.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bubble_type_ == BUBBLE_TYPE_DEFAULT) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bubble_view_->SetMaxHeight(0);  // Clear max height limit.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (scoped_layer) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // When transitioning from default view to detailed view, animate the new
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // view (slide in from the right).
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bubble_type == BUBBLE_TYPE_DETAILED) {
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::Layer* new_layer = bubble_view_->layer();
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Make sure the new layer is stacked above the old layer during the
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // animation.
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      new_layer->parent()->StackAbove(new_layer, scoped_layer.get());
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Rect bounds = new_layer->bounds();
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::Transform transform;
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      transform.Translate(bounds.width(), 0.0);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new_layer->SetTransform(transform);
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      {
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator());
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        settings.AddObserver(
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            new AnimationObserverDeleteLayer(scoped_layer.release()));
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        settings.SetTransitionDuration(
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::TimeDelta::FromMilliseconds(kSwipeDelayMS));
243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        settings.SetTweenType(gfx::Tween::EASE_OUT);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new_layer->SetTransform(gfx::Transform());
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::InitView(views::View* anchor,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                user::LoginStatus login_status,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                TrayBubbleView::InitParams* init_params) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bubble_view_ == NULL);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bubble_type_ == BUBBLE_TYPE_DETAILED &&
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      init_params->max_height < kDetailedBubbleMaxHeight) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    init_params->max_height = kDetailedBubbleMaxHeight;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (bubble_type_ == BUBBLE_TYPE_NOTIFICATION) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    init_params->close_on_deactivate = false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_view_ = TrayBubbleView::Create(
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tray_->GetBubbleWindowContainer(), anchor, tray_, init_params);
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bubble_view_->set_adjust_if_offscreen(false);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateItemViews(login_status);
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (bubble_view_->CanActivate()) {
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bubble_view_->NotifyAccessibilityEvent(
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        ui::AX_EVENT_ALERT, true);
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SystemTrayBubble::FocusDefaultIfNeeded() {
2730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  views::FocusManager* manager = bubble_view_->GetFocusManager();
274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!manager || manager->GetFocusedView())
2750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
2760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  views::View* view = manager->GetNextFocusableView(NULL, NULL, false, false);
2780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (view)
2790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    view->RequestFocus();
2800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::DestroyItemViews() {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != items_.end();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (bubble_type_) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BUBBLE_TYPE_DEFAULT:
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*it)->DestroyDefaultView();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BUBBLE_TYPE_DETAILED:
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*it)->DestroyDetailedView();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BUBBLE_TYPE_NOTIFICATION:
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*it)->DestroyNotificationView();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::BubbleViewDestroyed() {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble_view_ = NULL;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::StartAutoCloseTimer(int seconds) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  autoclose_.Stop();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  autoclose_delay_ = seconds;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (autoclose_delay_) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    autoclose_.Start(FROM_HERE,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     base::TimeDelta::FromSeconds(autoclose_delay_),
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     this, &SystemTrayBubble::Close);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::StopAutoCloseTimer() {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  autoclose_.Stop();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::RestartAutoCloseTimer() {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (autoclose_delay_)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartAutoCloseTimer(autoclose_delay_);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::Close() {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tray_->HideBubbleWithView(bubble_view());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::SetVisible(bool is_visible) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bubble_view_)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget* bubble_widget = bubble_view_->GetWidget();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visible)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bubble_widget->Show();
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bubble_widget->Hide();
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SystemTrayBubble::IsVisible() {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bubble_view() && bubble_view()->GetWidget()->IsVisible();
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool SystemTrayBubble::ShouldShowShelf() const {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<ash::SystemTrayItem*>::const_iterator it = items_.begin();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != items_.end();
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if ((*it)->ShouldShowShelf())
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemTrayBubble::CreateItemViews(user::LoginStatus login_status) {
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<views::View*> item_views;
353c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // If a system modal dialog is present, create the same tray as
354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // in locked state.
355c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (Shell::GetInstance()->IsSystemModalWindowOpen() &&
356c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      login_status != user::LOGGED_IN_NONE) {
357c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    login_status = user::LOGGED_IN_LOCKED;
358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  views::View* focus_view = NULL;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < items_.size(); ++i) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = NULL;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (bubble_type_) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BUBBLE_TYPE_DEFAULT:
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        view = items_[i]->CreateDefaultView(login_status);
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (items_[i]->restore_focus())
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          focus_view = view;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BUBBLE_TYPE_DETAILED:
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        view = items_[i]->CreateDetailedView(login_status);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BUBBLE_TYPE_NOTIFICATION:
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        view = items_[i]->CreateNotificationView(login_status);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (view)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item_views.push_back(view);
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_default_bubble = bubble_type_ == BUBBLE_TYPE_DEFAULT;
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < item_views.size(); ++i) {
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // For default view, draw bottom border for each item, except the last
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // 2 items, which are the bottom header row and the one just above it.
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bubble_view_->AddChildView(new TrayPopupItemContainer(
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        item_views[i], is_default_bubble,
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        is_default_bubble && (i < item_views.size() - 2)));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (focus_view)
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    focus_view->RequestFocus();
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
393