123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- // Copyright 2014 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/system/message_center/ash_message_popup_collection.h"
- #include <memory>
- #include <utility>
- #include <vector>
- #include "ash/keyboard/ui/keyboard_ui_controller.h"
- #include "ash/keyboard/ui/keyboard_util.h"
- #include "ash/public/cpp/keyboard/keyboard_switches.h"
- #include "ash/public/cpp/shelf_types.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/root_window_controller.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shell.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/wm/desks/desks_util.h"
- #include "ash/wm/overview/overview_controller.h"
- #include "base/command_line.h"
- #include "base/test/scoped_feature_list.h"
- #include "ui/display/manager/display_manager.h"
- #include "ui/display/screen.h"
- #include "ui/gfx/animation/linear_animation.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/message_center/message_center.h"
- #include "ui/message_center/public/cpp/message_center_constants.h"
- #include "ui/message_center/views/message_popup_collection.h"
- #include "ui/message_center/views/message_popup_view.h"
- namespace ash {
- namespace {
- class TestMessagePopupCollection : public AshMessagePopupCollection {
- public:
- explicit TestMessagePopupCollection(Shelf* shelf)
- : AshMessagePopupCollection(shelf) {}
- TestMessagePopupCollection(const TestMessagePopupCollection&) = delete;
- TestMessagePopupCollection& operator=(const TestMessagePopupCollection&) =
- delete;
- ~TestMessagePopupCollection() override = default;
- bool popup_shown() const { return popup_shown_; }
- protected:
- void NotifyPopupAdded(message_center::MessagePopupView* popup) override {
- AshMessagePopupCollection::NotifyPopupAdded(popup);
- popup_shown_ = true;
- notification_id_ = popup->message_view()->notification_id();
- }
- void NotifyPopupRemoved(const std::string& notification_id) override {
- AshMessagePopupCollection::NotifyPopupRemoved(notification_id);
- EXPECT_EQ(notification_id_, notification_id);
- popup_shown_ = false;
- notification_id_.clear();
- }
- private:
- bool popup_shown_ = false;
- std::string notification_id_;
- };
- } // namespace
- class AshMessagePopupCollectionTest : public AshTestBase,
- public testing::WithParamInterface<bool> {
- public:
- AshMessagePopupCollectionTest() = default;
- AshMessagePopupCollectionTest(const AshMessagePopupCollectionTest&) = delete;
- AshMessagePopupCollectionTest& operator=(
- const AshMessagePopupCollectionTest&) = delete;
- ~AshMessagePopupCollectionTest() override = default;
- void SetUp() override {
- scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
- scoped_feature_list_->InitWithFeatureState(features::kNotificationsRefresh,
- IsNotificationsRefreshEnabled());
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- keyboard::switches::kEnableVirtualKeyboard);
- AshTestBase::SetUp();
- SetPopupCollection(
- std::make_unique<AshMessagePopupCollection>(GetPrimaryShelf()));
- }
- void TearDown() override {
- popup_collection_.reset();
- AshTestBase::TearDown();
- }
- bool IsNotificationsRefreshEnabled() const { return GetParam(); }
- protected:
- enum Position { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, OUTSIDE };
- AshMessagePopupCollection* popup_collection() {
- return popup_collection_.get();
- }
- void UpdateWorkArea(AshMessagePopupCollection* popup_collection,
- const display::Display& display) {
- popup_collection->StartObserving(display::Screen::GetScreen(), display);
- // Update the layout
- popup_collection->UpdateWorkArea();
- }
- void SetPopupCollection(std::unique_ptr<AshMessagePopupCollection> delegate) {
- if (!delegate.get()) {
- popup_collection_.reset();
- return;
- }
- popup_collection_ = std::move(delegate);
- UpdateWorkArea(popup_collection_.get(),
- display::Screen::GetScreen()->GetPrimaryDisplay());
- }
- Position GetPositionInDisplay(const gfx::Point& point) {
- const gfx::Rect work_area =
- display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
- const gfx::Point center_point = work_area.CenterPoint();
- if (work_area.x() > point.x() || work_area.y() > point.y() ||
- work_area.right() < point.x() || work_area.bottom() < point.y()) {
- return OUTSIDE;
- }
- if (center_point.x() < point.x())
- return (center_point.y() < point.y()) ? BOTTOM_RIGHT : TOP_RIGHT;
- else
- return (center_point.y() < point.y()) ? BOTTOM_LEFT : TOP_LEFT;
- }
- gfx::Rect GetWorkArea() { return popup_collection_->work_area_; }
- std::unique_ptr<message_center::Notification> CreateNotification(
- const std::string& id) {
- return std::make_unique<message_center::Notification>(
- message_center::NOTIFICATION_TYPE_SIMPLE, id, u"test_title",
- u"test message", ui::ImageModel(),
- std::u16string() /* display_source */, GURL(),
- message_center::NotifierId(), message_center::RichNotificationData(),
- new message_center::NotificationDelegate());
- }
- std::string AddNotification() {
- std::string id = base::NumberToString(notification_id_++);
- message_center::MessageCenter::Get()->AddNotification(
- CreateNotification(id));
- return id;
- }
- private:
- int notification_id_ = 0;
- std::unique_ptr<AshMessagePopupCollection> popup_collection_;
- std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
- };
- INSTANTIATE_TEST_SUITE_P(All,
- AshMessagePopupCollectionTest,
- testing::Bool() /* IsNotificationsRefreshEnabled() */);
- TEST_P(AshMessagePopupCollectionTest, ShelfAlignment) {
- const gfx::Rect toast_size(0, 0, 10, 10);
- UpdateDisplay("601x600");
- gfx::Point toast_point;
- toast_point.set_x(popup_collection()->GetToastOriginX(toast_size));
- toast_point.set_y(popup_collection()->GetBaseline());
- EXPECT_EQ(BOTTOM_RIGHT, GetPositionInDisplay(toast_point));
- EXPECT_FALSE(popup_collection()->IsTopDown());
- EXPECT_FALSE(popup_collection()->IsFromLeft());
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kRight);
- toast_point.set_x(popup_collection()->GetToastOriginX(toast_size));
- toast_point.set_y(popup_collection()->GetBaseline());
- EXPECT_EQ(BOTTOM_RIGHT, GetPositionInDisplay(toast_point));
- EXPECT_FALSE(popup_collection()->IsTopDown());
- EXPECT_FALSE(popup_collection()->IsFromLeft());
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
- toast_point.set_x(popup_collection()->GetToastOriginX(toast_size));
- toast_point.set_y(popup_collection()->GetBaseline());
- EXPECT_EQ(BOTTOM_LEFT, GetPositionInDisplay(toast_point));
- EXPECT_FALSE(popup_collection()->IsTopDown());
- EXPECT_TRUE(popup_collection()->IsFromLeft());
- }
- TEST_P(AshMessagePopupCollectionTest, LockScreen) {
- const gfx::Rect toast_size(0, 0, 10, 10);
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
- gfx::Point toast_point;
- toast_point.set_x(popup_collection()->GetToastOriginX(toast_size));
- toast_point.set_y(popup_collection()->GetBaseline());
- EXPECT_EQ(BOTTOM_LEFT, GetPositionInDisplay(toast_point));
- EXPECT_FALSE(popup_collection()->IsTopDown());
- EXPECT_TRUE(popup_collection()->IsFromLeft());
- BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
- toast_point.set_x(popup_collection()->GetToastOriginX(toast_size));
- toast_point.set_y(popup_collection()->GetBaseline());
- EXPECT_EQ(BOTTOM_RIGHT, GetPositionInDisplay(toast_point));
- EXPECT_FALSE(popup_collection()->IsTopDown());
- EXPECT_FALSE(popup_collection()->IsFromLeft());
- }
- TEST_P(AshMessagePopupCollectionTest, AutoHide) {
- const gfx::Rect toast_size(0, 0, 10, 10);
- UpdateDisplay("601x600");
- int origin_x = popup_collection()->GetToastOriginX(toast_size);
- int baseline = popup_collection()->GetBaseline();
- // Create a window, otherwise autohide doesn't work.
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect(0, 0, 50, 50));
- Shelf* shelf = GetPrimaryShelf();
- shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
- EXPECT_EQ(origin_x, popup_collection()->GetToastOriginX(toast_size));
- EXPECT_LT(baseline, popup_collection()->GetBaseline());
- }
- TEST_P(AshMessagePopupCollectionTest, DisplayResize) {
- const gfx::Rect toast_size(0, 0, 10, 10);
- UpdateDisplay("601x600");
- int origin_x = popup_collection()->GetToastOriginX(toast_size);
- int baseline = popup_collection()->GetBaseline();
- UpdateDisplay("801x800");
- EXPECT_LT(origin_x, popup_collection()->GetToastOriginX(toast_size));
- EXPECT_LT(baseline, popup_collection()->GetBaseline());
- UpdateDisplay("500x400");
- EXPECT_GT(origin_x, popup_collection()->GetToastOriginX(toast_size));
- EXPECT_GT(baseline, popup_collection()->GetBaseline());
- }
- TEST_P(AshMessagePopupCollectionTest, DockedMode) {
- const gfx::Rect toast_size(0, 0, 10, 10);
- UpdateDisplay("601x600");
- int origin_x = popup_collection()->GetToastOriginX(toast_size);
- int baseline = popup_collection()->GetBaseline();
- // Emulate the docked mode; enter to an extended mode, then invoke
- // OnNativeDisplaysChanged() with the info for the secondary display only.
- UpdateDisplay("601x600,801x800");
- std::vector<display::ManagedDisplayInfo> new_info;
- new_info.push_back(display_manager()->GetDisplayInfo(
- display_manager()->GetDisplayAt(1u).id()));
- display_manager()->OnNativeDisplaysChanged(new_info);
- EXPECT_LT(origin_x, popup_collection()->GetToastOriginX(toast_size));
- EXPECT_LT(baseline, popup_collection()->GetBaseline());
- }
- TEST_P(AshMessagePopupCollectionTest, TrayHeight) {
- const gfx::Rect toast_size(0, 0, 10, 10);
- UpdateDisplay("601x600");
- int origin_x = popup_collection()->GetToastOriginX(toast_size);
- int baseline = popup_collection()->GetBaseline();
- // Simulate the system tray bubble being open.
- const int kTrayHeight = 100;
- popup_collection()->SetTrayBubbleHeight(kTrayHeight);
- EXPECT_EQ(origin_x, popup_collection()->GetToastOriginX(toast_size));
- EXPECT_EQ(baseline - kTrayHeight - message_center::kMarginBetweenPopups,
- popup_collection()->GetBaseline());
- }
- TEST_P(AshMessagePopupCollectionTest, Extended) {
- UpdateDisplay("601x600,801x800");
- SetPopupCollection(
- std::make_unique<AshMessagePopupCollection>(GetPrimaryShelf()));
- display::Display second_display = GetSecondaryDisplay();
- Shelf* second_shelf =
- Shell::GetRootWindowControllerWithDisplayId(second_display.id())->shelf();
- AshMessagePopupCollection for_2nd_display(second_shelf);
- UpdateWorkArea(&for_2nd_display, second_display);
- // Make sure that the toast position on the secondary display is
- // positioned correctly.
- EXPECT_LT(1300, for_2nd_display.GetToastOriginX(gfx::Rect(0, 0, 10, 10)));
- EXPECT_LT(700, for_2nd_display.GetBaseline());
- }
- TEST_P(AshMessagePopupCollectionTest, MixedFullscreenNone) {
- UpdateDisplay("601x600,801x800");
- Shelf* shelf1 = GetPrimaryShelf();
- TestMessagePopupCollection collection1(shelf1);
- UpdateWorkArea(&collection1, GetPrimaryDisplay());
- Shelf* shelf2 =
- Shell::GetRootWindowControllerWithDisplayId(GetSecondaryDisplay().id())
- ->shelf();
- TestMessagePopupCollection collection2(shelf2);
- UpdateWorkArea(&collection2, GetSecondaryDisplay());
- // No fullscreens, both receive notification.
- std::unique_ptr<views::Widget> widget1 = CreateTestWidget();
- widget1->SetFullscreen(false);
- AddNotification();
- EXPECT_TRUE(collection1.popup_shown());
- EXPECT_TRUE(collection2.popup_shown());
- // Set screen 1 to fullscreen, popup closes on screen 1, stays on screen 2.
- widget1->SetFullscreen(true);
- EXPECT_FALSE(collection1.popup_shown());
- EXPECT_TRUE(collection2.popup_shown());
- }
- TEST_P(AshMessagePopupCollectionTest, MixedFullscreenSome) {
- UpdateDisplay("601x600,801x800");
- Shelf* shelf1 = GetPrimaryShelf();
- TestMessagePopupCollection collection1(shelf1);
- UpdateWorkArea(&collection1, GetPrimaryDisplay());
- Shelf* shelf2 =
- Shell::GetRootWindowControllerWithDisplayId(GetSecondaryDisplay().id())
- ->shelf();
- TestMessagePopupCollection collection2(shelf2);
- UpdateWorkArea(&collection2, GetSecondaryDisplay());
- // One fullscreen, non-fullscreen receives notification.
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->SetFullscreen(true);
- AddNotification();
- EXPECT_FALSE(collection1.popup_shown());
- EXPECT_TRUE(collection2.popup_shown());
- // Fullscreen toggles, notification now on both.
- widget->SetFullscreen(false);
- EXPECT_TRUE(collection1.popup_shown());
- EXPECT_TRUE(collection2.popup_shown());
- }
- TEST_P(AshMessagePopupCollectionTest, MixedFullscreenAll) {
- UpdateDisplay("601x600,801x800");
- Shelf* shelf1 = GetPrimaryShelf();
- TestMessagePopupCollection collection1(shelf1);
- UpdateWorkArea(&collection1, GetPrimaryDisplay());
- Shelf* shelf2 =
- Shell::GetRootWindowControllerWithDisplayId(GetSecondaryDisplay().id())
- ->shelf();
- TestMessagePopupCollection collection2(shelf2);
- UpdateWorkArea(&collection2, GetSecondaryDisplay());
- std::unique_ptr<views::Widget> widget1 = CreateTestWidget();
- std::unique_ptr<views::Widget> widget2 =
- CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
- gfx::Rect(700, 0, 50, 50));
- // Both fullscreen, no notifications.
- widget1->SetFullscreen(true);
- widget2->SetFullscreen(true);
- AddNotification();
- EXPECT_FALSE(collection1.popup_shown());
- EXPECT_FALSE(collection2.popup_shown());
- // Toggle 1, then the other.
- widget1->SetFullscreen(false);
- EXPECT_TRUE(collection1.popup_shown());
- EXPECT_FALSE(collection2.popup_shown());
- widget2->SetFullscreen(false);
- EXPECT_TRUE(collection1.popup_shown());
- EXPECT_TRUE(collection2.popup_shown());
- }
- TEST_P(AshMessagePopupCollectionTest, Unified) {
- display_manager()->SetUnifiedDesktopEnabled(true);
- // Reset the delegate as the primary display's shelf will be destroyed during
- // transition.
- SetPopupCollection(nullptr);
- UpdateDisplay("601x600,801x800");
- SetPopupCollection(
- std::make_unique<AshMessagePopupCollection>(GetPrimaryShelf()));
- EXPECT_GT(600, popup_collection()->GetToastOriginX(gfx::Rect(0, 0, 10, 10)));
- }
- // Tests that when the keyboard is showing that notifications appear above it,
- // and that they return to normal once the keyboard is gone.
- TEST_P(AshMessagePopupCollectionTest, KeyboardShowing) {
- ASSERT_TRUE(keyboard::IsKeyboardEnabled());
- ASSERT_TRUE(
- keyboard::KeyboardUIController::Get()->IsKeyboardOverscrollEnabled());
- UpdateDisplay("601x600");
- int baseline = popup_collection()->GetBaseline();
- Shelf* shelf = GetPrimaryShelf();
- gfx::Rect keyboard_bounds(0, 300, 601, 300);
- shelf->SetVirtualKeyboardBoundsForTesting(keyboard_bounds);
- int keyboard_baseline = popup_collection()->GetBaseline();
- EXPECT_NE(baseline, keyboard_baseline);
- EXPECT_GT(keyboard_bounds.y(), keyboard_baseline);
- shelf->SetVirtualKeyboardBoundsForTesting(gfx::Rect());
- EXPECT_EQ(baseline, popup_collection()->GetBaseline());
- }
- // Tests that notification bubble baseline is correct when entering and exiting
- // overview with a full screen window.
- TEST_P(AshMessagePopupCollectionTest, BaselineInOverview) {
- UpdateDisplay("800x600");
- ASSERT_TRUE(GetPrimaryShelf()->IsHorizontalAlignment());
- ASSERT_EQ(SHELF_VISIBLE, GetPrimaryShelf()->GetVisibilityState());
- const int baseline_with_visible_shelf = popup_collection()->GetBaseline();
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->SetFullscreen(true);
- ASSERT_EQ(SHELF_HIDDEN, GetPrimaryShelf()->GetVisibilityState());
- const int baseline_with_hidden_shelf = popup_collection()->GetBaseline();
- EXPECT_NE(baseline_with_visible_shelf, baseline_with_hidden_shelf);
- auto* overview_controller = Shell::Get()->overview_controller();
- EnterOverview();
- EXPECT_TRUE(overview_controller->InOverviewSession());
- const int baseline_in_overview = popup_collection()->GetBaseline();
- EXPECT_EQ(baseline_in_overview, baseline_with_visible_shelf);
- ExitOverview();
- EXPECT_FALSE(overview_controller->InOverviewSession());
- const int baseline_no_overview = popup_collection()->GetBaseline();
- EXPECT_EQ(baseline_no_overview, baseline_with_hidden_shelf);
- }
- } // namespace ash
|