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