blob: 4149a8a9e48c99d06a8736c3978768f44a060ae8 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/message_center/message_center_view.h"
#include <list>
#include <map>
#include "ash/message_center/message_center_button_bar.h"
#include "ash/message_center/message_center_style.h"
#include "ash/message_center/notifier_settings_view.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_types.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/views/message_view.h"
#include "ui/message_center/views/message_view_factory.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
using message_center::MessageCenter;
using message_center::MessageView;
using message_center::Notification;
using message_center::NotificationList;
namespace ash {
// static
const size_t MessageCenterView::kMaxVisibleNotifications = 100;
// static
bool MessageCenterView::disable_animation_for_testing = false;
namespace {
constexpr int kMinScrollViewHeight = 77;
constexpr int kEmptyViewHeight = 96;
constexpr gfx::Insets kEmptyViewPadding(0, 0, 24, 0);
constexpr int kScrollShadowOffsetY = -2;
constexpr int kScrollShadowBlur = 2;
constexpr SkColor kScrollShadowColor = SkColorSetA(SK_ColorBLACK, 0x24);
void SetViewHierarchyEnabled(views::View* view, bool enabled) {
for (int i = 0; i < view->child_count(); i++)
SetViewHierarchyEnabled(view->child_at(i), enabled);
view->SetEnabled(enabled);
}
// Create a view that is shown when there are no notifications.
views::View* CreateEmptyNotificationView() {
auto* view = new views::View;
auto layout = std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical,
kEmptyViewPadding, 0);
layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
layout->set_cross_axis_alignment(
views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
view->SetLayoutManager(std::move(layout));
views::ImageView* icon = new views::ImageView();
icon->SetImage(gfx::CreateVectorIcon(kNotificationCenterAllDoneIcon,
message_center_style::kEmptyIconSize,
message_center_style::kEmptyViewColor));
icon->SetBorder(
views::CreateEmptyBorder(message_center_style::kEmptyIconPadding));
view->AddChildView(icon);
views::Label* label = new views::Label(
l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_NO_MESSAGES));
label->SetEnabledColor(message_center_style::kEmptyViewColor);
// "Roboto-Medium, 12sp" is specified in the mock.
label->SetFontList(
gfx::FontList().DeriveWithWeight(gfx::Font::Weight::MEDIUM));
label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
label->SetSubpixelRenderingEnabled(false);
view->AddChildView(label);
view->SetPaintToLayer();
view->layer()->SetFillsBoundsOpaquely(false);
return view;
}
class MessageCenterScrollView : public views::ScrollView {
public:
MessageCenterScrollView(MessageCenterView* owner) : owner_(owner) {}
~MessageCenterScrollView() override = default;
private:
// views::View:
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
node_data->role = ax::mojom::Role::kDialog;
node_data->SetName(
l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_FOOTER_TITLE));
}
// views::ScrollBarController:
void ScrollToPosition(views::ScrollBar* source, int position) override {
views::ScrollView::ScrollToPosition(source, position);
owner_->UpdateScrollerShadowVisibility();
}
MessageCenterView* const owner_;
DISALLOW_COPY_AND_ASSIGN(MessageCenterScrollView);
};
// A view that displays a shadow at the bottom when |scroller_| is bounded.
class ScrollShadowView : public views::View {
public:
ScrollShadowView(int max_scroll_view_height, int button_height)
: max_scroll_view_height_(max_scroll_view_height),
button_height_(button_height) {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
set_can_process_events_within_subtree(false);
}
~ScrollShadowView() override = default;
protected:
void PaintChildren(const views::PaintInfo& paint_info) override {
views::View::PaintChildren(paint_info);
if (height() != max_scroll_view_height_)
return;
// Draw a shadow at the bottom of the viewport when scrolled.
DrawShadow(paint_info.context(),
gfx::Rect(0, height(), width(), button_height_));
}
private:
// Draws a drop shadow above |shadowed_area|.
void DrawShadow(const ui::PaintContext& context,
const gfx::Rect& shadowed_area) {
ui::PaintRecorder recorder(context, size());
gfx::Canvas* canvas = recorder.canvas();
cc::PaintFlags flags;
gfx::ShadowValues shadow;
shadow.emplace_back(gfx::Vector2d(0, kScrollShadowOffsetY),
kScrollShadowBlur, kScrollShadowColor);
flags.setLooper(gfx::CreateShadowDrawLooper(shadow));
flags.setAntiAlias(true);
canvas->ClipRect(shadowed_area, SkClipOp::kDifference);
canvas->DrawRect(shadowed_area, flags);
}
const int max_scroll_view_height_;
const int button_height_;
DISALLOW_COPY_AND_ASSIGN(ScrollShadowView);
};
} // namespace
// MessageCenterView ///////////////////////////////////////////////////////////
MessageCenterView::MessageCenterView(
MessageCenter* message_center,
int max_height,
bool initially_settings_visible)
: message_center_(message_center),
settings_visible_(initially_settings_visible),
is_locked_(Shell::Get()->session_controller()->IsScreenLocked()) {
if (is_locked_ && !features::IsLockScreenNotificationsEnabled())
mode_ = Mode::LOCKED;
else if (initially_settings_visible)
mode_ = Mode::SETTINGS;
message_center_->AddObserver(this);
set_notify_enter_exit_on_child(true);
SetFocusBehavior(views::View::FocusBehavior::NEVER);
button_bar_ = new MessageCenterButtonBar(
this, message_center, initially_settings_visible, is_locked_);
button_bar_->SetCloseAllButtonEnabled(false);
const int button_height = button_bar_->GetPreferredSize().height();
const int max_scroll_view_height = max_height - button_height;
scroller_shadow_ =
new ScrollShadowView(max_scroll_view_height, button_height);
scroller_ = new MessageCenterScrollView(this);
// Need to set the transparent background explicitly, since ScrollView has
// set the default opaque background color.
scroller_->SetBackgroundColor(SK_ColorTRANSPARENT);
scroller_->ClipHeightTo(kMinScrollViewHeight, max_scroll_view_height);
scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
scroller_->SetHorizontalScrollBar(new views::OverlayScrollBar(true));
message_list_view_.reset(new MessageListView());
message_list_view_->set_scroller(scroller_);
message_list_view_->set_owned_by_client();
message_list_view_->AddObserver(this);
// We want to swap the contents of the scroll view between the empty list
// view and the message list view, without constructing them afresh each
// time. So, since the scroll view deletes old contents each time you
// set the contents (regardless of the |owned_by_client_| setting) we need
// an intermediate view for the contents whose children we can swap in and
// out.
views::View* scroller_contents = new views::View();
scroller_contents->SetLayoutManager(std::make_unique<views::FillLayout>());
scroller_contents->AddChildView(message_list_view_.get());
scroller_->SetContents(scroller_contents);
settings_view_ = new NotifierSettingsView();
no_notifications_view_ = CreateEmptyNotificationView();
scroller_->SetVisible(false); // Because it has no notifications at first.
settings_view_->SetVisible(mode_ == Mode::SETTINGS);
no_notifications_view_->SetVisible(mode_ == Mode::NO_NOTIFICATIONS);
AddChildView(no_notifications_view_);
AddChildView(scroller_);
AddChildView(scroller_shadow_);
AddChildView(settings_view_);
AddChildView(button_bar_);
if (switches::IsSidebarEnabled())
MessageView::SetSidebarEnabled();
}
MessageCenterView::~MessageCenterView() {
message_list_view_->RemoveObserver(this);
if (!is_closing_)
message_center_->RemoveObserver(this);
if (focus_manager_)
focus_manager_->RemoveFocusChangeListener(this);
}
void MessageCenterView::Init() {
focus_manager_ = GetFocusManager();
if (focus_manager_)
focus_manager_->AddFocusChangeListener(this);
}
void MessageCenterView::SetNotifications(
const NotificationList::Notifications& notifications) {
if (is_closing_)
return;
int index = 0;
for (NotificationList::Notifications::const_iterator iter =
notifications.begin();
iter != notifications.end(); ++iter) {
AddNotificationAt(*(*iter), index++);
message_center_->DisplayedNotification(
(*iter)->id(), message_center::DISPLAY_SOURCE_MESSAGE_CENTER);
if (message_list_view_->GetNotificationCount() >=
kMaxVisibleNotifications) {
break;
}
}
Update(false /* animate */);
scroller_->RequestFocus();
}
void MessageCenterView::SetSettingsVisible(bool visible) {
settings_visible_ = visible;
Update(true /* animate */);
}
void MessageCenterView::ClearAllClosableNotifications() {
if (is_closing_)
return;
is_clearing_all_notifications_ = true;
UpdateButtonBarStatus();
SetViewHierarchyEnabled(scroller_, false);
message_list_view_->ClearAllClosableNotifications(
scroller_->GetVisibleRect());
}
void MessageCenterView::OnLockStateChanged(bool locked) {
is_locked_ = locked;
Update(true /* animate */);
// Refresh a11y information, because accessible name of the view changes.
NotifyAccessibilityEvent(ax::mojom::Event::kAriaAttributeChanged, true);
}
void MessageCenterView::OnAllNotificationsCleared() {
SetViewHierarchyEnabled(scroller_, true);
button_bar_->SetCloseAllButtonEnabled(false);
// The status of buttons will be updated after removing all notifications.
// Action by user.
message_center_->RemoveAllNotifications(
true /* by_user */, MessageCenter::RemoveType::NON_PINNED);
is_clearing_all_notifications_ = false;
}
size_t MessageCenterView::NumMessageViewsForTest() const {
return message_list_view_->GetNotificationCount();
}
void MessageCenterView::OnSettingsChanged() {
scroller_->InvalidateLayout();
PreferredSizeChanged();
Layout();
}
void MessageCenterView::SetIsClosing(bool is_closing) {
is_closing_ = is_closing;
if (is_closing)
message_center_->RemoveObserver(this);
else
message_center_->AddObserver(this);
}
void MessageCenterView::OnDidChangeFocus(views::View* before,
views::View* now) {
// Update the button visibility when the focus state is changed.
size_t count = message_list_view_->GetNotificationCount();
for (size_t i = 0; i < count; ++i) {
MessageView* view = message_list_view_->GetNotificationAt(i);
// ControlButtonsView is not in the same view hierarchy on ARC++
// notifications, so check it separately.
if (view->Contains(before) || view->Contains(now) ||
(view->GetControlButtonsView() &&
(view->GetControlButtonsView()->Contains(before) ||
view->GetControlButtonsView()->Contains(now)))) {
view->UpdateControlButtonsVisibility();
}
// Ensure that a notification is not removed or added during iteration.
DCHECK_EQ(count, message_list_view_->GetNotificationCount());
}
}
void MessageCenterView::UpdateScrollerShadowVisibility() {
// |scroller_shadow_| is visible only if |scroller_| is not all scrolled.
scroller_shadow_->SetVisible(scroller_->contents()->height() +
scroller_->contents()->y() !=
scroller_shadow_->height());
}
void MessageCenterView::Layout() {
if (is_closing_)
return;
int button_height = button_bar_->GetHeightForWidth(width());
int settings_height =
std::min(GetSettingsHeightForWidth(width()), height() - button_height);
// In order to keep the fix for https://crbug.com/767805 working,
// we have to always call SetBounds of scroller_.
// TODO(tetsui): Fix the bug above without calling SetBounds, as SetBounds
// invokes Layout() which is a heavy operation.
scroller_->SetBounds(0, 0, width(), height() - button_height);
scroller_shadow_->SetBounds(0, 0, width(), height() - button_height);
if (settings_view_->visible()) {
settings_view_->SetBounds(0, height() - settings_height, width(),
settings_height);
}
if (no_notifications_view_->visible())
no_notifications_view_->SetBounds(0, 0, width(), kEmptyViewHeight);
button_bar_->SetBounds(0, height() - button_height - settings_height, width(),
button_height);
if (GetWidget())
GetWidget()->GetRootView()->SchedulePaint();
}
gfx::Size MessageCenterView::CalculatePreferredSize() const {
int width = 0;
for (int i = 0; i < child_count(); ++i) {
const views::View* child = child_at(i);
if (child->visible())
width = std::max(width, child->GetPreferredSize().width());
}
return gfx::Size(width, GetHeightForWidth(width));
}
int MessageCenterView::GetHeightForWidth(int width) const {
if (settings_transition_animation_ &&
settings_transition_animation_->is_animating()) {
return button_bar_->GetHeightForWidth(width) +
GetContentHeightDuringAnimation();
}
return button_bar_->GetHeightForWidth(width) +
GetContentHeightForMode(mode_, width);
}
bool MessageCenterView::OnMouseWheel(const ui::MouseWheelEvent& event) {
// Do not rely on the default scroll event handler of ScrollView because
// the scroll happens only when the focus is on the ScrollView. The
// notification center will allow the scrolling even when the focus is on
// the buttons.
if (scroller_->bounds().Contains(event.location()))
return scroller_->OnMouseWheel(event);
return views::View::OnMouseWheel(event);
}
void MessageCenterView::OnMouseExited(const ui::MouseEvent& event) {
if (is_closing_)
return;
message_list_view_->ResetRepositionSession();
Update(true /* animate */);
}
void MessageCenterView::OnNotificationAdded(const std::string& id) {
int index = 0;
const NotificationList::Notifications& notifications =
message_center_->GetVisibleNotifications();
for (NotificationList::Notifications::const_iterator
iter = notifications.begin();
iter != notifications.end(); ++iter, ++index) {
if ((*iter)->id() == id) {
AddNotificationAt(*(*iter), index);
break;
}
if (message_list_view_->GetNotificationCount() >=
kMaxVisibleNotifications) {
break;
}
}
Update(true /* animate */);
}
void MessageCenterView::OnNotificationRemoved(const std::string& id,
bool by_user) {
auto view_pair = message_list_view_->GetNotificationById(id);
MessageView* view = view_pair.second;
if (!view)
return;
size_t index = view_pair.first;
// We skip repositioning during clear-all anomation, since we don't need keep
// positions.
if (by_user && !is_clearing_all_notifications_) {
message_list_view_->SetRepositionTarget(view->bounds());
// Moves the keyboard focus to the next notification if the removed
// notification is focused so that the user can dismiss notifications
// without re-focusing by tab key.
if (view->IsCloseButtonFocused() || view->HasFocus()) {
views::View* next_focused_view = nullptr;
if (message_list_view_->GetNotificationCount() > index + 1)
next_focused_view = message_list_view_->GetNotificationAt(index + 1);
else if (index > 0)
next_focused_view = message_list_view_->GetNotificationAt(index - 1);
if (next_focused_view) {
if (view->IsCloseButtonFocused()) {
// Safe cast since all views in MessageListView are MessageViews.
static_cast<MessageView*>(next_focused_view)
->RequestFocusOnCloseButton();
} else {
next_focused_view->RequestFocus();
}
}
}
}
message_list_view_->RemoveNotification(view);
Update(true /* animate */);
}
// This is a separate function so we can override it in tests.
bool MessageCenterView::SetRepositionTarget() {
// Set the item on the mouse cursor as the reposition target so that it
// should stick to the current position over the update.
if (message_list_view_->IsMouseHovered()) {
size_t count = message_list_view_->GetNotificationCount();
for (size_t i = 0; i < count; ++i) {
const views::View* hover_view = message_list_view_->GetNotificationAt(i);
if (hover_view->IsMouseHovered()) {
message_list_view_->SetRepositionTarget(hover_view->bounds());
return true;
}
}
}
return false;
}
void MessageCenterView::OnNotificationUpdated(const std::string& id) {
// If there is no reposition target anymore, make sure to reset the reposition
// session.
if (!SetRepositionTarget())
message_list_view_->ResetRepositionSession();
UpdateNotification(id);
}
void MessageCenterView::OnQuietModeChanged(bool is_quiet_mode) {
settings_view_->SetQuietModeState(is_quiet_mode);
button_bar_->SetQuietModeState(is_quiet_mode);
}
void MessageCenterView::AnimationEnded(const gfx::Animation* animation) {
DCHECK_EQ(animation, settings_transition_animation_.get());
message_center::Visibility visibility =
mode_ == Mode::SETTINGS ? message_center::VISIBILITY_SETTINGS
: message_center::VISIBILITY_MESSAGE_CENTER;
message_center_->SetVisibility(visibility);
if (source_view_) {
source_view_->SetVisible(false);
}
if (target_view_)
target_view_->SetVisible(true);
if (settings_transition_animation_)
NotifyAnimationState(false /* animating */);
settings_transition_animation_.reset();
PreferredSizeChanged();
Layout();
// We should update minimum fixed height based on new |scroller_| height.
// This is required when switching between message list and settings panel.
if (!scroller_->visible())
message_list_view_->ResetRepositionSession();
}
void MessageCenterView::AnimationProgressed(const gfx::Animation* animation) {
DCHECK_EQ(animation, settings_transition_animation_.get());
PreferredSizeChanged();
Layout();
SchedulePaint();
}
void MessageCenterView::AnimationCanceled(const gfx::Animation* animation) {
DCHECK_EQ(animation, settings_transition_animation_.get());
AnimationEnded(animation);
}
void MessageCenterView::OnViewPreferredSizeChanged(views::View* observed_view) {
DCHECK_EQ(std::string(MessageView::kViewClassName),
observed_view->GetClassName());
UpdateNotification(
static_cast<MessageView*>(observed_view)->notification_id());
}
void MessageCenterView::AddNotificationAt(const Notification& notification,
int index) {
MessageView* view = message_center::MessageViewFactory::Create(
notification, false); // Not top-level.
view->AddObserver(this);
view->set_scroller(scroller_);
message_list_view_->AddNotificationAt(view, index);
}
void MessageCenterView::Update(bool animate) {
bool no_message_views = (message_list_view_->GetNotificationCount() == 0);
if (is_locked_ && !features::IsLockScreenNotificationsEnabled())
SetVisibilityMode(Mode::LOCKED, animate);
else if (settings_visible_)
SetVisibilityMode(Mode::SETTINGS, animate);
else if (no_message_views)
SetVisibilityMode(Mode::NO_NOTIFICATIONS, animate);
else
SetVisibilityMode(Mode::NOTIFICATIONS, animate);
UpdateButtonBarStatus();
if (scroller_->visible())
scroller_->InvalidateLayout();
PreferredSizeChanged();
Layout();
}
void MessageCenterView::SetVisibilityMode(Mode mode, bool animate) {
if (is_closing_)
return;
if (mode == mode_)
return;
switch (mode_) {
case Mode::NOTIFICATIONS:
source_view_ = scroller_;
break;
case Mode::SETTINGS:
source_view_ = settings_view_;
break;
case Mode::LOCKED:
source_view_ = nullptr;
break;
case Mode::NO_NOTIFICATIONS:
source_view_ = no_notifications_view_;
break;
}
switch (mode) {
case Mode::NOTIFICATIONS:
target_view_ = scroller_;
break;
case Mode::SETTINGS:
target_view_ = settings_view_;
break;
case Mode::LOCKED:
target_view_ = nullptr;
break;
case Mode::NO_NOTIFICATIONS:
target_view_ = no_notifications_view_;
break;
}
source_height_ = GetContentHeightForMode(mode_, width());
target_height_ = GetContentHeightForMode(mode, width());
mode_ = mode;
int contents_max_height =
max_height_ - button_bar_->GetPreferredSize().height();
source_height_ = std::min(contents_max_height, source_height_);
target_height_ = std::min(contents_max_height, target_height_);
if (source_view_)
source_view_->SetVisible(true);
if (target_view_)
target_view_->SetVisible(true);
if (!animate || disable_animation_for_testing) {
AnimationEnded(nullptr);
return;
}
NotifyAnimationState(true /* animating */);
settings_transition_animation_ = std::make_unique<gfx::SlideAnimation>(this);
settings_transition_animation_->SetSlideDuration(
message_center_style::kSettingsTransitionDurationMs);
settings_transition_animation_->SetTweenType(gfx::Tween::EASE_IN_OUT);
settings_transition_animation_->Show();
}
void MessageCenterView::UpdateButtonBarStatus() {
// Disables all buttons during animation of cleaning of all notifications.
if (is_clearing_all_notifications_) {
button_bar_->SetSettingsAndQuietModeButtonsEnabled(false);
button_bar_->SetCloseAllButtonEnabled(false);
return;
}
button_bar_->SetBackArrowVisible(mode_ == Mode::SETTINGS);
button_bar_->SetIsLocked(is_locked_);
EnableCloseAllIfAppropriate();
}
void MessageCenterView::EnableCloseAllIfAppropriate() {
if (mode_ == Mode::NOTIFICATIONS) {
bool no_closable_views = true;
size_t count = message_list_view_->GetNotificationCount();
for (size_t i = 0; i < count; ++i) {
if (!message_list_view_->GetNotificationAt(i)->GetPinned()) {
no_closable_views = false;
break;
}
}
button_bar_->SetCloseAllButtonEnabled(!no_closable_views);
} else {
// Disable the close-all button since no notification is visible.
button_bar_->SetCloseAllButtonEnabled(false);
}
}
void MessageCenterView::SetNotificationViewForTest(MessageView* view) {
message_list_view_->AddNotificationAt(view, 0);
}
void MessageCenterView::UpdateNotification(const std::string& id) {
MessageView* view = message_list_view_->GetNotificationById(id).second;
if (!view)
return;
Notification* notification = message_center_->FindVisibleNotificationById(id);
if (notification) {
int old_width = view->width();
int old_height = view->height();
bool old_pinned = view->GetPinned();
message_list_view_->UpdateNotification(view, *notification);
if (view->GetHeightForWidth(old_width) != old_height) {
Update(true /* animate */);
} else if (view->GetPinned() != old_pinned) {
// Animate flag is false, since the pinned flag transition doesn't need
// animation.
Update(false /* animate */);
}
}
// Notify accessibility that the contents have changed.
view->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
}
void MessageCenterView::NotifyAnimationState(bool animating) {
size_t count = message_list_view_->GetNotificationCount();
for (size_t i = 0; i < count; ++i) {
MessageView* view = message_list_view_->GetNotificationAt(i);
if (animating)
view->OnContainerAnimationStarted();
else
view->OnContainerAnimationEnded();
// Ensure that a notification is not removed or added during iteration.
DCHECK_EQ(count, message_list_view_->GetNotificationCount());
}
}
int MessageCenterView::GetSettingsHeightForWidth(int width) const {
if (settings_transition_animation_ &&
settings_transition_animation_->is_animating() &&
(source_view_ == settings_view_ || target_view_ == settings_view_)) {
return settings_transition_animation_->CurrentValueBetween(
target_view_ == settings_view_ ? 0 : source_height_,
source_view_ == settings_view_ ? 0 : target_height_);
} else {
return mode_ == Mode::SETTINGS ? settings_view_->GetHeightForWidth(width)
: 0;
}
}
int MessageCenterView::GetContentHeightDuringAnimation() const {
DCHECK(settings_transition_animation_);
int contents_height = settings_transition_animation_->CurrentValueBetween(
target_view_ == settings_view_ ? 0 : source_height_,
source_view_ == settings_view_ ? 0 : target_height_);
if (target_view_ == settings_view_)
contents_height = std::max(source_height_, contents_height);
if (source_view_ == settings_view_)
contents_height = std::max(target_height_, contents_height);
return contents_height;
}
int MessageCenterView::GetContentHeightForMode(Mode mode, int width) const {
switch (mode) {
case Mode::NOTIFICATIONS:
return scroller_->GetHeightForWidth(width);
case Mode::SETTINGS:
return settings_view_->GetHeightForWidth(width);
case Mode::LOCKED:
return 0;
case Mode::NO_NOTIFICATIONS:
return kEmptyViewHeight;
}
}
} // namespace ash