1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
#include <cstddef>
#include <memory>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/notification_view_controller.h"
#include "ui/message_center/views/message_view.h"
#include "ui/views/widget/widget.h"
namespace gfx {
class LinearAnimation;
} // namespace gfx
namespace display {
class Display;
} // namespace display
namespace message_center {
class MessagePopupView;
class Notification;
class PopupAlignmentDelegate;
// Container of notification popups usually shown at the right bottom of the
// screen. Manages animation state and updates these popup widgets.
class MESSAGE_CENTER_EXPORT MessagePopupCollection
: public MessageCenterObserver,
public NotificationViewController,
public gfx::AnimationDelegate {
public:
MessagePopupCollection();
MessagePopupCollection(const MessagePopupCollection& other) = delete;
MessagePopupCollection& operator=(const MessagePopupCollection& other) =
delete;
~MessagePopupCollection() override;
// Update popups based on current |state_|.
void Update();
// Reset all popup positions. Called from PopupAlignmentDelegate when
// alignment and work area might be changed.
void ResetBounds();
// Notify the popup size is changed. Called from MessagePopupView.
void NotifyPopupResized();
// Notify the popup is closed. Called from MessagePopupView.
virtual void NotifyPopupClosed(MessagePopupView* popup);
// NotificationViewController:
void AnimateResize() override;
MessageView* GetMessageViewForNotificationId(
const std::string& notification_id) override;
void ConvertNotificationViewToGroupedNotificationView(
const std::string& ungrouped_notification_id,
const std::string& new_grouped_notification_id) override;
void ConvertGroupedNotificationViewToNotificationView(
const std::string& grouped_notification_id,
const std::string& new_single_notification_id) override;
void OnChildNotificationViewUpdated(
const std::string& parent_notification_id,
const std::string& child_notification_id) override;
// MessageCenterObserver:
void OnNotificationAdded(const std::string& notification_id) override;
void OnNotificationRemoved(const std::string& notification_id,
bool by_user) override;
void OnNotificationUpdated(const std::string& notification_id) override;
void OnCenterVisibilityChanged(Visibility visibility) override;
void OnBlockingStateChanged(NotificationBlocker* blocker) override;
// AnimationDelegate:
void AnimationEnded(const gfx::Animation* animation) override;
void AnimationProgressed(const gfx::Animation* animation) override;
void AnimationCanceled(const gfx::Animation* animation) override;
// Find the message popup view for the given notification id. Return nullptr
// if it does not exist.
MessagePopupView* GetPopupViewForNotificationID(
const std::string& notification_id);
// Called when a new popup appears or popups are rearranged in the |display|.
// The subclass may override this method to check the current desktop status
// so that the popups are arranged at the correct place. Return true if
// alignment is actually changed.
virtual bool RecomputeAlignment(const display::Display& display) = 0;
// Sets the parent container for popups. If it does not set a parent a
// default parent will be used (e.g. the native desktop on Windows).
virtual void ConfigureWidgetInitParamsForContainer(
views::Widget* widget,
views::Widget::InitParams* init_params) = 0;
size_t GetPopupItemsCount();
gfx::Rect popup_collection_bounds() { return popup_collection_bounds_; }
protected:
// Stores animation related state of a popup.
struct PopupItem {
PopupItem();
PopupItem(const PopupItem&) = delete;
PopupItem(PopupItem&& other);
PopupItem& operator=(const PopupItem&) = delete;
PopupItem& operator=(PopupItem&&);
~PopupItem();
// Notification ID.
std::string id;
// The bounds that the popup starts animating from.
// If |is_animating| is false, it is ignored. Also the value is only used
// when the animation type is kFadeIn or kMoveDown.
gfx::Rect start_bounds;
// The final bounds of the popup.
gfx::Rect bounds;
// If the popup is animating.
bool is_animating = false;
// Unowned.
raw_ptr<MessagePopupView, DanglingUntriaged> popup = nullptr;
std::unique_ptr<views::Widget> widget;
};
// Returns the x-origin for the given popup bounds in the current work area.
virtual int GetPopupOriginX(const gfx::Rect& popup_bounds) const = 0;
// Returns the baseline height of the current work area. That is the starting
// point if there are no other popups.
virtual int GetBaseline() const = 0;
// Returns the rect of the current work area.
virtual gfx::Rect GetWorkArea() const = 0;
// Returns true if the popup should be aligned top down.
virtual bool IsTopDown() const = 0;
// Returns true if the popups are positioned at the left side of the desktop
// so that their reveal animation should happen from left side.
virtual bool IsFromLeft() const = 0;
// Returns true if the display which notifications show on is the primary
// display.
virtual bool IsPrimaryDisplayForNotification() const = 0;
// Returns true if |notification| should be blocked because this display to
// show the notification is fullscreen. If all (1 of 1, or n of n) displays
// are fullscreen, the notification will already be blocked by the associated
// FullscreenNotificationBlocker, but this function is required for the case
// where there are multiple displays, and the notification should be blocked
// on those that are fullscreen, but displayed on the others.
//
// This function can return false when only a single display is supported
// since FullscreenNotificationBlocker will have already blocked anything.
virtual bool BlockForMixedFullscreen(
const Notification& notification) const = 0;
// Called when a new popup item is added.
virtual void NotifyPopupAdded(MessagePopupView* popup) {}
// Called with |notification_id| when a popup is marked to be removed.
virtual void NotifyPopupRemoved(const std::string& notification_id) {}
// Called when an incoming notification is sent directly to the notification
// center (e.g. its priority is too low for a popup to be generated for it).
// `notification_id` is the ID of the notification.
virtual void NotifySilentNotification(const std::string& notification_id) {}
// Called when the entire popup collection change its height.
virtual void NotifyPopupCollectionHeightChanged() {}
// Called when popup animation is started/finished.
virtual void AnimationStarted() {}
virtual void AnimationFinished() {}
// TODO(crbug/1241602): std::unique_ptr can be used here and multiple other
// places.
virtual MessagePopupView* CreatePopup(const Notification& notification);
// Returns true if the edge is outside work area.
bool IsNextEdgeOutsideWorkArea(const PopupItem& item) const;
// Called to close a particular popup item.
virtual void ClosePopupItem(PopupItem& item);
// Marks `is_animating` flag of all popups for `kMoveDown` animation.
void MoveDownPopups();
// virtual for testing.
virtual void RestartPopupTimers();
virtual void PausePopupTimers();
// Stops all the animation and closes all the popups immediately.
void CloseAllPopupsNow();
gfx::LinearAnimation* animation() { return animation_.get(); }
const std::vector<PopupItem>& popup_items() { return popup_items_; }
private:
friend class MessagePopupCollectionTest;
// MessagePopupCollection always runs single animation at one time.
// State is an enum of which animation is running right now.
// If |state_| is kIdle, animation_->is_animating() is always false and vice
// versa.
enum class State {
// No animation is running.
kIdle,
// Fading in an added notification.
kFadeIn,
// Fading out a removed notification. After the animation, if there are
// still remaining notifications, it will transition to kMoveDown.
kFadeOut,
// Moving down notifications. Notification collapsing and resizing are also
// done in kMoveDown.
kMoveDown,
};
// Transition from animation state (kFadeIn, kFadeOut, and kMoveDown) to
// kIdle state or next animation state (kMoveDown).
void TransitionFromAnimation();
// Transition from kIdle state to animation state (kFadeIn, kFadeOut or
// kMoveDown).
void TransitionToAnimation();
// Pause or restart popup timers depending on |state_|.
void UpdatePopupTimers();
// Calculate and update the bounds for all popups, including moving old
// `bounds` to `start_bounds` and updating `popup_collection_bounds_`.
void CalculateAndUpdateBounds();
// Update bounds and opacity of popups during animation.
void UpdateByAnimation();
// Get popup notifications in sort order from MessageCenter, filtered for any
// that should not show on this display.
std::vector<Notification*> GetPopupNotifications() const;
// Add a new popup to |popup_items_| for kFadeIn animation.
// Return true if a popup is actually added. It may still return false when
// HasAddedPopup() return true by the lack of work area to show popup.
bool AddPopup();
// Mark |is_animating| flag of removed popup to true for kFadeOut animation.
void MarkRemovedPopup();
// Get the y-axis edge of the new popup. In usual bottom-to-top layout, it
// means the topmost y-axis when |item| is added.
int GetNextEdge(const PopupItem& item) const;
void CloseAnimatingPopups();
bool CloseTransparentPopups();
void ClosePopupsOutsideWorkArea();
void RemoveClosedPopupItems();
void CloseAndRemovePopupFromPopupItem(MessagePopupView* popup,
bool remove_only = false);
// Collapse all existing popups. Return true if size of any popup is actually
// changed.
bool CollapseAllPopups();
// Return true if there is a new popup to add.
bool HasAddedPopup() const;
// Return true is there is a old popup to remove.
bool HasRemovedPopup() const;
// Return true if any popup is hovered by mouse.
bool IsAnyPopupHovered() const;
// Return true if any popup is focused.
bool IsAnyPopupFocused() const;
// Returns the popup which is visually |index_from_top|-th from the top.
PopupItem* GetPopupItem(size_t index_from_top);
// Reset |recently_closed_by_user_| to false. Used by
// |recently_closed_by_user_timer_|
void ResetRecentlyClosedByUser();
// Animation state. See the comment of State.
State state_ = State::kIdle;
// Covers all animation performed by MessagePopupCollection. When the
// animation is running, it is always one of kFadeIn (sliding in and opacity
// change), kFadeOut (opacity change), and kMoveDown (sliding down).
// MessagePopupCollection does not use implicit animation. The position and
// opacity changes are explicitly set from UpdateByAnimation().
const std::unique_ptr<gfx::LinearAnimation> animation_;
// Notification popups. The first element is the oldest one.
std::vector<PopupItem> popup_items_;
// True during Update() to avoid reentrancy. For example, popup size change
// might be notified during Update() because Update() changes popup sizes, but
// popup might change the size by itself e.g. expanding notification by mouse.
bool is_updating_ = false;
// If true, popup sizes are resized on the next time Update() is called with
// kIdle state.
bool resize_requested_ = false;
// The bounds of the entire popup collection.
gfx::Rect popup_collection_bounds_;
base::ScopedObservation<MessageCenter, MessageCenterObserver>
message_center_observation_{this};
base::WeakPtrFactory<MessagePopupCollection> weak_ptr_factory_{this};
};
} // namespace message_center
#endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_COLLECTION_H_
|