12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/views/message_popup_collection.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <set> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/i18n/rtl.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/weak_ptr.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/run_loop.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_enums.h" 17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_delegate.h" 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/screen.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center.h" 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/message_center/message_center_style.h" 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/message_center_tray.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification_list.h" 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/views/message_view_context_menu_controller.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/views/notification_view.h" 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/message_center/views/popup_alignment_delegate.h" 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/views/toast_contents_view.h" 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/background.h" 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/fill_layout.h" 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/view.h" 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/views/views_delegate.h" 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/widget/widget.h" 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/widget/widget_delegate.h" 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace message_center { 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Timeout between the last user-initiated close of the toast and the moment 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// when normal layout/update of the toast stack continues. If the last toast was 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// just closed, the timeout is shorter. 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kMouseExitedDeferTimeoutMs = 200; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// The margin between messages (and between the anchor unless 45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// first_item_has_no_margin was specified). 46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst int kToastMarginY = kMarginBetweenItems; 47bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 50116680a4aac90f2aa7413d9095a592090648e557Ben MurdochMessagePopupCollection::MessagePopupCollection( 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch gfx::NativeView parent, 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MessageCenter* message_center, 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MessageCenterTray* tray, 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch PopupAlignmentDelegate* alignment_delegate) 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : parent_(parent), 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center_(message_center), 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch tray_(tray), 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch alignment_delegate_(alignment_delegate), 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) defer_counter_(0), 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latest_toast_entered_(NULL), 61bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch user_is_closing_toasts_by_clicking_(false), 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) context_menu_controller_(new MessageViewContextMenuController(this)), 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) weak_factory_(this) { 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(message_center_); 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) defer_timer_.reset(new base::OneShotTimer<MessagePopupCollection>); 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center_->AddObserver(this); 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch alignment_delegate_->set_collection(this); 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)MessagePopupCollection::~MessagePopupCollection() { 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) weak_factory_.InvalidateWeakPtrs(); 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center_->RemoveObserver(this); 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CloseAllWidgets(); 76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MessagePopupCollection::ClickOnNotification( 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& notification_id) { 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) message_center_->ClickOnNotification(notification_id); 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MessagePopupCollection::RemoveNotification( 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& notification_id, 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool by_user) { 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) message_center_->RemoveNotification(notification_id, by_user); 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<ui::MenuModel> MessagePopupCollection::CreateMenuModel( 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const NotifierId& notifier_id, 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& display_source) { 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return tray_->CreateNotificationMenuModel(notifier_id, display_source); 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool MessagePopupCollection::HasClickedListener( 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& notification_id) { 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return message_center_->HasClickedListener(notification_id); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MessagePopupCollection::ClickOnNotificationButton( 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& notification_id, 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int button_index) { 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) message_center_->ClickOnNotificationButton(notification_id, button_index); 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MessagePopupCollection::MarkAllPopupsShown() { 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::set<std::string> closed_ids = CloseAllWidgets(); 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (std::set<std::string>::iterator iter = closed_ids.begin(); 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) iter != closed_ids.end(); iter++) { 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) message_center_->MarkSinglePopupAsShown(*iter, false); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::UpdateWidgets() { 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NotificationList::PopupNotifications popups = 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center_->GetPopupNotifications(); 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (popups.empty()) { 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseAllWidgets(); 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool top_down = alignment_delegate_->IsTopDown(); 124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) int base = GetBaseLine(toasts_.empty() ? NULL : toasts_.back()); 125bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Iterate in the reverse order to keep the oldest toasts on screen. Newer 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // items may be ignored if there are no room to place them. 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (NotificationList::PopupNotifications::const_reverse_iterator iter = 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) popups.rbegin(); iter != popups.rend(); ++iter) { 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (FindToast((*iter)->id())) 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) continue; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NotificationView* view = 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NotificationView::Create(NULL, 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *(*iter), 1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) true); // Create top-level notification. 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view->set_context_menu_controller(context_menu_controller_.get()); 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int view_height = ToastContentsView::GetToastSizeForView(view).height(); 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int height_available = 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch top_down ? alignment_delegate_->GetWorkAreaBottom() - base : base; 141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (height_available - view_height - kToastMarginY < 0) { 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) delete view; 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ToastContentsView* toast = 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new ToastContentsView((*iter)->id(), weak_factory_.GetWeakPtr()); 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // There will be no contents already since this is a new ToastContentsView. 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) toast->SetContents(view, /*a11y_feedback_for_updates=*/false); 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) toasts_.push_back(toast); 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view->set_controller(toast); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gfx::Size preferred_size = toast->GetPreferredSize(); 155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch gfx::Point origin( 156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch alignment_delegate_->GetToastOriginX(gfx::Rect(preferred_size)), base); 157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // The toast slides in from the edge of the screen horizontally. 158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (alignment_delegate_->IsFromLeft()) 159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) origin.set_x(origin.x() - preferred_size.width()); 160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) else 161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) origin.set_x(origin.x() + preferred_size.width()); 162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (top_down) 163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) origin.set_y(origin.y() + view_height); 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) toast->RevealWithAnimation(origin); 166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Shift the base line to be a few pixels above the last added toast or (few 168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // pixels below last added toast if top-aligned). 169a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (top_down) 170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base += view_height + kToastMarginY; 171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) else 172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base -= view_height + kToastMarginY; 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (views::ViewsDelegate::views_delegate) { 175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) views::ViewsDelegate::views_delegate->NotifyAccessibilityEvent( 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) toast, ui::AX_EVENT_ALERT); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) message_center_->DisplayedNotification( 180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) (*iter)->id(), message_center::DISPLAY_SOURCE_POPUP); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::OnMouseEntered(ToastContentsView* toast_entered) { 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Sometimes we can get two MouseEntered/MouseExited in a row when animating 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // toasts. So we need to keep track of which one is the currently active one. 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latest_toast_entered_ = toast_entered; 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) message_center_->PausePopupTimers(); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (user_is_closing_toasts_by_clicking_) 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) defer_timer_->Stop(); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::OnMouseExited(ToastContentsView* toast_exited) { 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If we're exiting a toast after entering a different toast, then ignore 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // this mouse event. 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (toast_exited != latest_toast_entered_) 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latest_toast_entered_ = NULL; 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (user_is_closing_toasts_by_clicking_) { 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) defer_timer_->Start( 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FROM_HERE, 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kMouseExitedDeferTimeoutMs), 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) this, 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &MessagePopupCollection::OnDeferTimerExpired); 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) message_center_->RestartPopupTimers(); 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::set<std::string> MessagePopupCollection::CloseAllWidgets() { 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::set<std::string> closed_toast_ids; 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) while (!toasts_.empty()) { 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ToastContentsView* toast = toasts_.front(); 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) toasts_.pop_front(); 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) closed_toast_ids.insert(toast->id()); 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) OnMouseExited(toast); 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // CloseWithAnimation will cause the toast to forget about |this| so it is 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // required when we forget a toast. 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) toast->CloseWithAnimation(); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return closed_toast_ids; 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MessagePopupCollection::ForgetToast(ToastContentsView* toast) { 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) toasts_.remove(toast); 233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) OnMouseExited(toast); 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MessagePopupCollection::RemoveToast(ToastContentsView* toast, 237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool mark_as_shown) { 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ForgetToast(toast); 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) toast->CloseWithAnimation(); 241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mark_as_shown) 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) message_center_->MarkSinglePopupAsShown(toast->id(), false); 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::RepositionWidgets() { 247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool top_down = alignment_delegate_->IsTopDown(); 248a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) int base = GetBaseLine(NULL); // We don't want to position relative to last 249a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // toast - we want re-position. 250bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end();) { 252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Toasts::const_iterator curr = iter++; 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect bounds((*curr)->bounds()); 254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bounds.set_x(alignment_delegate_->GetToastOriginX(bounds)); 255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bounds.set_y(top_down ? base : base - bounds.height()); 256a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // The notification may scrolls the boundary of the screen due to image 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // load and such notifications should disappear. Do not call 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // CloseWithAnimation, we don't want to show the closing animation, and we 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // don't want to mark such notifications as shown. See crbug.com/233424 261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if ((top_down ? alignment_delegate_->GetWorkAreaBottom() - bounds.bottom() 262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : bounds.y()) >= 0) 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (*curr)->SetBoundsWithAnimation(bounds); 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RemoveToast(*curr, /*mark_as_shown=*/false); 266a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 267a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Shift the base line to be a few pixels above the last added toast or (few 268a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // pixels below last added toast if top-aligned). 269a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (top_down) 270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base += bounds.height() + kToastMarginY; 271a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) else 272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base -= bounds.height() + kToastMarginY; 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::RepositionWidgetsWithTarget() { 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (toasts_.empty()) 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool top_down = alignment_delegate_->IsTopDown(); 281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Nothing to do if there are no widgets above target if bottom-aligned or no 283a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // widgets below target if top-aligned. 284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (top_down ? toasts_.back()->origin().y() < target_top_edge_ 285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) : toasts_.back()->origin().y() > target_top_edge_) 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Toasts::reverse_iterator iter = toasts_.rbegin(); 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (; iter != toasts_.rend(); ++iter) { 290a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // We only reposition widgets above target if bottom-aligned or widgets 291a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // below target if top-aligned. 292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (top_down ? (*iter)->origin().y() < target_top_edge_ 293a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) : (*iter)->origin().y() > target_top_edge_) 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) --iter; 297a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 298a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Slide length is the number of pixels the widgets should move so that their 299a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // bottom edge (top-edge if top-aligned) touches the target. 300a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) int slide_length = std::abs(target_top_edge_ - (*iter)->origin().y()); 301a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (;; --iter) { 302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Rect bounds((*iter)->bounds()); 303a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 304a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // If top-aligned, shift widgets upwards by slide_length. If bottom-aligned, 305a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // shift them downwards by slide_length. 306a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (top_down) 307a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bounds.set_y(bounds.y() - slide_length); 308a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) else 309a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bounds.set_y(bounds.y() + slide_length); 310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) (*iter)->SetBoundsWithAnimation(bounds); 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (iter == toasts_.rbegin()) 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int MessagePopupCollection::GetBaseLine(ToastContentsView* last_toast) const { 318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!last_toast) { 319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return alignment_delegate_->GetBaseLine(); 320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } else if (alignment_delegate_->IsTopDown()) { 321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return toasts_.back()->bounds().bottom() + kToastMarginY; 322a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return toasts_.back()->origin().y() - kToastMarginY; 324a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 325a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 326a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::OnNotificationAdded( 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& notification_id) { 329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoUpdateIfPossible(); 330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::OnNotificationRemoved( 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& notification_id, 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool by_user) { 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Find a toast. 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Toasts::const_iterator iter = toasts_.begin(); 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (; iter != toasts_.end(); ++iter) { 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((*iter)->id() == notification_id) 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (iter == toasts_.end()) 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) target_top_edge_ = (*iter)->bounds().y(); 3454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (by_user && !user_is_closing_toasts_by_clicking_) { 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // [Re] start a timeout after which the toasts re-position to their 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // normal locations after tracking the mouse pointer for easy deletion. 348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This provides a period of time when toasts are easy to remove because 349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // they re-position themselves to have Close button right under the mouse 350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // pointer. If the user continue to remove the toasts, the delay is reset. 351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Once user stopped removing the toasts, the toasts re-populate/rearrange 352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // after the specified delay. 3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) user_is_closing_toasts_by_clicking_ = true; 3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IncrementDeferCounter(); 355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // CloseWithAnimation ultimately causes a call to RemoveToast, which calls 3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // OnMouseExited. This means that |user_is_closing_toasts_by_clicking_| must 3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // have been set before this call, otherwise it will remain true even after 3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // the toast is closed, since the defer timer won't be started. 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RemoveToast(*iter, /*mark_as_shown=*/true); 3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (by_user) 3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) RepositionWidgetsWithTarget(); 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::OnDeferTimerExpired() { 368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_is_closing_toasts_by_clicking_ = false; 369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DecrementDeferCounter(); 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) message_center_->RestartPopupTimers(); 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::OnNotificationUpdated( 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& notification_id) { 376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Find a toast. 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Toasts::const_iterator toast_iter = toasts_.begin(); 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (; toast_iter != toasts_.end(); ++toast_iter) { 379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((*toast_iter)->id() == notification_id) 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (toast_iter == toasts_.end()) 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NotificationList::PopupNotifications notifications = 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) message_center_->GetPopupNotifications(); 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool updated = false; 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (NotificationList::PopupNotifications::iterator iter = 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) notifications.begin(); iter != notifications.end(); ++iter) { 3910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) Notification* notification = *iter; 3920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) DCHECK(notification); 3930de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) ToastContentsView* toast_contents_view = *toast_iter; 3940de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) DCHECK(toast_contents_view); 3950de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) 3960de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) if (notification->id() != notification_id) 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) continue; 398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const RichNotificationData& optional_fields = 4000de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) notification->rich_notification_data(); 401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool a11y_feedback_for_updates = 402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) optional_fields.should_make_spoken_feedback_for_popup_updates; 403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 4040de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) toast_contents_view->UpdateContents(*notification, 4050de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) a11y_feedback_for_updates); 4060de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) 407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) updated = true; 408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // OnNotificationUpdated() can be called when a notification is excluded from 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // the popup notification list but still remains in the full notification 412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // list. In that case the widget for the notification has to be closed here. 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!updated) 414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RemoveToast(*toast_iter, /*mark_as_shown=*/true); 415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (user_is_closing_toasts_by_clicking_) 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RepositionWidgetsWithTarget(); 418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoUpdateIfPossible(); 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ToastContentsView* MessagePopupCollection::FindToast( 423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& notification_id) const { 424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end(); 425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ++iter) { 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((*iter)->id() == notification_id) 427868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return *iter; 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 429868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NULL; 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::IncrementDeferCounter() { 433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) defer_counter_++; 434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::DecrementDeferCounter() { 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) defer_counter_--; 438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(defer_counter_ >= 0); 439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoUpdateIfPossible(); 440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This is the main sequencer of tasks. It does a step, then waits for 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// all started transitions to play out before doing the next step. 444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// First, remove all expired toasts. 445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Then, reposition widgets (the reposition on close happens before all 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// deferred tasks are even able to run) 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Then, see if there is vacant space for new toasts. 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MessagePopupCollection::DoUpdateIfPossible() { 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (defer_counter_ > 0) 450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RepositionWidgets(); 453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (defer_counter_ > 0) 455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Reposition could create extra space which allows additional widgets. 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) UpdateWidgets(); 459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (defer_counter_ > 0) 461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Test support. Quit the test run loop when no more updates are deferred, 464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // meaining th echeck for updates did not cause anything to change so no new 465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // transition animations were started. 466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (run_loop_for_test_.get()) 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) run_loop_for_test_->Quit(); 468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void MessagePopupCollection::OnDisplayMetricsChanged( 471116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const gfx::Display& display) { 472116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch alignment_delegate_->RecomputeAlignment(display); 473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)views::Widget* MessagePopupCollection::GetWidgetForTest(const std::string& id) 476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const { 477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end(); 478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ++iter) { 479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((*iter)->id() == id) 480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return (*iter)->GetWidget(); 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MessagePopupCollection::CreateRunLoopForTest() { 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) run_loop_for_test_.reset(new base::RunLoop()); 487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MessagePopupCollection::WaitForTest() { 490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) run_loop_for_test_->Run(); 491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) run_loop_for_test_.reset(); 492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Rect MessagePopupCollection::GetToastRectAt(size_t index) const { 495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(defer_counter_ == 0) << "Fetching the bounds with animations active."; 496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t i = 0; 497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end(); 498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ++iter) { 499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (i++ == index) { 500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::Widget* widget = (*iter)->GetWidget(); 501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (widget) 502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return widget->GetWindowBoundsInScreen(); 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return gfx::Rect(); 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace message_center 510