| // Copyright 2012 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/containers/circular_deque.h" | 
 | #include "base/run_loop.h" | 
 | #include "base/strings/string_number_conversions.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "base/strings/utf_string_conversions.h" | 
 | #include "build/build_config.h" | 
 | #include "chrome/browser/apps/app_service/app_launch_params.h" | 
 | #include "chrome/browser/apps/app_service/app_service_proxy.h" | 
 | #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" | 
 | #include "chrome/browser/apps/app_service/browser_app_launcher.h" | 
 | #include "chrome/browser/extensions/api/notifications/extension_notification_display_helper.h" | 
 | #include "chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h" | 
 | #include "chrome/browser/extensions/api/notifications/extension_notification_handler.h" | 
 | #include "chrome/browser/extensions/api/notifications/notifications_api.h" | 
 | #include "chrome/browser/extensions/extension_apitest.h" | 
 | #include "chrome/browser/notifications/notification_display_service_tester.h" | 
 | #include "chrome/browser/notifications/notification_handler.h" | 
 | #include "chrome/browser/notifications/notifier_state_tracker.h" | 
 | #include "chrome/browser/notifications/notifier_state_tracker_factory.h" | 
 | #include "chrome/browser/profiles/profile.h" | 
 | #include "components/services/app_service/public/cpp/app_launch_util.h" | 
 | #include "content/public/test/browser_test.h" | 
 | #include "extensions/browser/api/test/test_api.h" | 
 | #include "extensions/browser/api_test_utils.h" | 
 | #include "extensions/browser/app_window/app_window.h" | 
 | #include "extensions/browser/app_window/app_window_registry.h" | 
 | #include "extensions/browser/app_window/native_app_window.h" | 
 | #include "extensions/browser/extension_host.h" | 
 | #include "extensions/browser/extension_host_test_helper.h" | 
 | #include "extensions/buildflags/buildflags.h" | 
 | #include "extensions/common/extension_builder.h" | 
 | #include "extensions/common/features/feature.h" | 
 | #include "extensions/common/mojom/view_type.mojom.h" | 
 | #include "extensions/test/extension_test_message_listener.h" | 
 | #include "extensions/test/result_catcher.h" | 
 | #include "ui/message_center/public/cpp/notification.h" | 
 | #include "ui/message_center/public/cpp/notifier_id.h" | 
 |  | 
 | #if BUILDFLAG(IS_MAC) | 
 | #include "base/mac/mac_util.h" | 
 | #endif | 
 |  | 
 | #if BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 | #include "chrome/browser/apps/platform_apps/app_browsertest_util.h" | 
 | #include "chrome/browser/ui/browser.h" | 
 | #include "chrome/test/base/interactive_test_utils.h" | 
 | #endif  // BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 |  | 
 | static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); | 
 |  | 
 | using extensions::AppWindow; | 
 | using extensions::AppWindowRegistry; | 
 | using extensions::Extension; | 
 | using extensions::ExtensionNotificationDisplayHelper; | 
 | using extensions::ExtensionNotificationDisplayHelperFactory; | 
 | using extensions::ResultCatcher; | 
 |  | 
 | namespace utils = extensions::api_test_utils; | 
 |  | 
 | namespace { | 
 |  | 
 | enum class WindowState { | 
 |   FULLSCREEN, | 
 |   NORMAL | 
 | }; | 
 |  | 
 | class NotificationsApiTest : public extensions::ExtensionApiTest { | 
 |  public: | 
 |   NotificationsApiTest() = default; | 
 |   ~NotificationsApiTest() override = default; | 
 |   NotificationsApiTest(const NotificationsApiTest&) = delete; | 
 |   NotificationsApiTest& operator=(const NotificationsApiTest&) = delete; | 
 |  | 
 |   const Extension* LoadExtensionAndWait( | 
 |       const std::string& test_name) { | 
 |     base::FilePath extdir = test_data_dir_.AppendASCII(test_name); | 
 |     extensions::ExtensionHostTestHelper host_helper(profile()); | 
 |     host_helper.RestrictToType( | 
 |         extensions::mojom::ViewType::kExtensionBackgroundPage); | 
 |     const extensions::Extension* extension = LoadExtension(extdir); | 
 |     if (extension) { | 
 |       host_helper.WaitForDocumentElementAvailable(); | 
 |     } | 
 |     return extension; | 
 |   } | 
 |  | 
 | #if BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 |   const Extension* LoadAppWithWindowState( | 
 |       const std::string& test_name, WindowState window_state) { | 
 |     const char* window_state_string = nullptr; | 
 |     switch (window_state) { | 
 |       case WindowState::FULLSCREEN: | 
 |         window_state_string = "fullscreen"; | 
 |         break; | 
 |       case WindowState::NORMAL: | 
 |         window_state_string = "normal"; | 
 |         break; | 
 |     } | 
 |     const std::string& create_window_options = base::StringPrintf( | 
 |         "{\"state\":\"%s\"}", window_state_string); | 
 |     base::FilePath extdir = test_data_dir_.AppendASCII(test_name); | 
 |     const extensions::Extension* extension = LoadExtension(extdir); | 
 |     EXPECT_TRUE(extension); | 
 |  | 
 |     ExtensionTestMessageListener launched_listener("launched", | 
 |                                                    ReplyBehavior::kWillReply); | 
 |     LaunchPlatformApp(extension); | 
 |     EXPECT_TRUE(launched_listener.WaitUntilSatisfied()); | 
 |     launched_listener.Reply(create_window_options); | 
 |  | 
 |     return extension; | 
 |   } | 
 |  | 
 |   AppWindow* GetFirstAppWindow(const std::string& app_id) { | 
 |     AppWindowRegistry::AppWindowList app_windows = | 
 |         AppWindowRegistry::Get(profile())->GetAppWindowsForApp(app_id); | 
 |  | 
 |     AppWindowRegistry::const_iterator iter = app_windows.begin(); | 
 |     if (iter != app_windows.end()) | 
 |       return *iter; | 
 |  | 
 |     return nullptr; | 
 |   } | 
 | #endif  // BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 |  | 
 |   ExtensionNotificationDisplayHelper* GetDisplayHelper() { | 
 |     return ExtensionNotificationDisplayHelperFactory::GetForProfile(profile()); | 
 |   } | 
 |  | 
 |   NotifierStateTracker* GetNotifierStateTracker() { | 
 |     return NotifierStateTrackerFactory::GetForProfile(profile()); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void SetUpOnMainThread() override { | 
 |     extensions::ExtensionApiTest::SetUpOnMainThread(); | 
 |  | 
 |     DCHECK(profile()); | 
 |     display_service_tester_ = | 
 |         std::make_unique<NotificationDisplayServiceTester>(profile()); | 
 |   } | 
 |  | 
 |   void TearDownOnMainThread() override { | 
 |     display_service_tester_.reset(); | 
 |     extensions::ExtensionApiTest::TearDownOnMainThread(); | 
 |   } | 
 |  | 
 |   // Returns the notification that's being displayed for |extension|, or nullptr | 
 |   // when the notification count is not equal to one. It's not safe to rely on | 
 |   // the Notification pointer after closing the notification, but a copy can be | 
 |   // made to continue to be able to access the underlying information. | 
 |   message_center::Notification* GetNotificationForExtension( | 
 |       const extensions::Extension* extension) { | 
 |     DCHECK(extension); | 
 |  | 
 |     std::set<std::string> notifications = | 
 |         GetDisplayHelper()->GetNotificationIdsForExtension(extension->url()); | 
 |     if (notifications.size() != 1) | 
 |       return nullptr; | 
 |  | 
 |     return GetDisplayHelper()->GetByNotificationId(*notifications.begin()); | 
 |   } | 
 |  | 
 |   std::string GetNotificationIdFromDelegateId(const std::string& delegate_id) { | 
 |     return GetDisplayHelper()->GetByNotificationId(delegate_id)->id(); | 
 |   } | 
 |  | 
 | #if BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 |   void LaunchPlatformApp(const Extension* extension) { | 
 |     apps::AppServiceProxyFactory::GetForProfile(profile()) | 
 |         ->BrowserAppLauncher() | 
 |         ->LaunchAppWithParamsForTesting(apps::AppLaunchParams( | 
 |             extension->id(), apps::LaunchContainer::kLaunchContainerNone, | 
 |             WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest)); | 
 |   } | 
 | #endif  // BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 |  | 
 |   std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_; | 
 | }; | 
 |  | 
 | // TODO(crbug.com/40170747): We should merge this class with the base | 
 | // class once the issues mentioned in the bug are resolved. | 
 | using NotificationsApiTestWithServiceWorker = NotificationsApiTest; | 
 |  | 
 | }  // namespace | 
 |  | 
 | // Flaky on TSan, see crbug.com/1304777. | 
 | #if BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER) | 
 | #define MAYBE_TestEvents DISABLED_TestEvents | 
 | #else | 
 | #define MAYBE_TestEvents TestEvents | 
 | #endif | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTestWithServiceWorker, | 
 |                        MAYBE_TestEvents) { | 
 |   ASSERT_TRUE(RunExtensionTest("notifications/api/events")) << message_; | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTestWithServiceWorker, TestBasicUsage) { | 
 |   ASSERT_TRUE(RunExtensionTest("notifications/api/basic_usage")) << message_; | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTestWithServiceWorker, TestCSP) { | 
 |   ASSERT_TRUE(RunExtensionTest("notifications/api/csp")) << message_; | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTestWithServiceWorker, | 
 |                        TestPartialUpdate) { | 
 |   ASSERT_TRUE(RunExtensionTest("notifications/api/partial_update")) << message_; | 
 |   const extensions::Extension* extension = GetSingleLoadedExtension(); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |  | 
 |   const char16_t kNewTitle[] = u"Changed!"; | 
 |   const char16_t kNewMessage[] = u"Too late! The show ended yesterday"; | 
 |   int kNewPriority = 2; | 
 |   const char16_t kButtonTitle[] = u"NewButton"; | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   EXPECT_EQ(kNewTitle, notification->title()); | 
 |   EXPECT_EQ(kNewMessage, notification->message()); | 
 |   EXPECT_EQ(kNewPriority, notification->priority()); | 
 |   EXPECT_TRUE(notification->silent()); | 
 |   EXPECT_EQ(1u, notification->buttons().size()); | 
 |   EXPECT_EQ(kButtonTitle, notification->buttons()[0].title); | 
 | } | 
 |  | 
 | // Native notifications don't support (or use) observers. | 
 | #if !BUILDFLAG(IS_MAC) | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestByUser) { | 
 |   const extensions::Extension* extension = | 
 |       LoadExtensionAndWait("notifications/api/by_user"); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |  | 
 |   { | 
 |     ResultCatcher catcher; | 
 |     const std::string notification_id = | 
 |         GetNotificationIdFromDelegateId(extension->id() + "-FOO"); | 
 |     display_service_tester_->RemoveNotification( | 
 |         NotificationHandler::Type::EXTENSION, notification_id, | 
 |         false /* by_user */); | 
 |     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | 
 |   } | 
 |  | 
 |   { | 
 |     ResultCatcher catcher; | 
 |     const std::string notification_id = | 
 |         GetNotificationIdFromDelegateId(extension->id() + "-BAR"); | 
 |     display_service_tester_->RemoveNotification( | 
 |         NotificationHandler::Type::EXTENSION, notification_id, | 
 |         true /* by_user */); | 
 |     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | 
 |   } | 
 |  | 
 |   { | 
 |     ResultCatcher catcher; | 
 |     display_service_tester_->RemoveAllNotifications( | 
 |         NotificationHandler::Type::EXTENSION, false /* by_user */); | 
 |     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | 
 |   } | 
 |   { | 
 |     ResultCatcher catcher; | 
 |     display_service_tester_->RemoveAllNotifications( | 
 |         NotificationHandler::Type::EXTENSION, true /* by_user */); | 
 |     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | 
 |   } | 
 | } | 
 | #endif  // !BUILDFLAG(IS_MAC) | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestGetPermissionLevel) { | 
 |   scoped_refptr<const Extension> empty_extension( | 
 |       extensions::ExtensionBuilder("Test").Build()); | 
 |  | 
 |   // Get permission level for the extension whose notifications are enabled. | 
 |   { | 
 |     scoped_refptr<extensions::NotificationsGetPermissionLevelFunction> | 
 |         notification_function( | 
 |             new extensions::NotificationsGetPermissionLevelFunction()); | 
 |  | 
 |     notification_function->set_extension(empty_extension.get()); | 
 |     notification_function->set_has_callback(true); | 
 |  | 
 |     std::optional<base::Value> result = utils::RunFunctionAndReturnSingleResult( | 
 |         notification_function.get(), "[]", profile(), | 
 |         extensions::api_test_utils::FunctionMode::kNone); | 
 |  | 
 |     EXPECT_EQ(base::Value::Type::STRING, result->type()); | 
 |     EXPECT_TRUE(result->is_string()); | 
 |     EXPECT_EQ("granted", result->GetString()); | 
 |   } | 
 |  | 
 |   // Get permission level for the extension whose notifications are disabled. | 
 |   { | 
 |     scoped_refptr<extensions::NotificationsGetPermissionLevelFunction> | 
 |         notification_function( | 
 |             new extensions::NotificationsGetPermissionLevelFunction()); | 
 |  | 
 |     notification_function->set_extension(empty_extension.get()); | 
 |     notification_function->set_has_callback(true); | 
 |  | 
 |     message_center::NotifierId notifier_id( | 
 |         message_center::NotifierType::APPLICATION, empty_extension->id()); | 
 |     GetNotifierStateTracker()->SetNotifierEnabled(notifier_id, false); | 
 |  | 
 |     std::optional<base::Value> result = utils::RunFunctionAndReturnSingleResult( | 
 |         notification_function.get(), "[]", profile(), | 
 |         extensions::api_test_utils::FunctionMode::kNone); | 
 |  | 
 |     EXPECT_EQ(base::Value::Type::STRING, result->type()); | 
 |     EXPECT_TRUE(result->is_string()); | 
 |     EXPECT_EQ("denied", result->GetString()); | 
 |   } | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestOnPermissionLevelChanged) { | 
 |   const extensions::Extension* extension = | 
 |       LoadExtensionAndWait("notifications/api/permission"); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |  | 
 |   // Test permission level changing from granted to denied. | 
 |   { | 
 |     ResultCatcher catcher; | 
 |  | 
 |     message_center::NotifierId notifier_id( | 
 |         message_center::NotifierType::APPLICATION, extension->id()); | 
 |     GetNotifierStateTracker()->SetNotifierEnabled(notifier_id, false); | 
 |  | 
 |     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | 
 |   } | 
 |  | 
 |   // Test permission level changing from denied to granted. | 
 |   { | 
 |     ResultCatcher catcher; | 
 |  | 
 |     message_center::NotifierId notifier_id( | 
 |         message_center::NotifierType::APPLICATION, extension->id()); | 
 |     GetNotifierStateTracker()->SetNotifierEnabled(notifier_id, true); | 
 |  | 
 |     EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | 
 |   } | 
 | } | 
 |  | 
 | // Native notifications don't support (nor use) observers. | 
 | #if !BUILDFLAG(IS_MAC) | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestUserGesture) { | 
 |   const extensions::Extension* extension = | 
 |       LoadExtensionAndWait("notifications/api/user_gesture"); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   { | 
 |     ExtensionTestMessageListener listener; | 
 |     // Action button event. | 
 |     display_service_tester_->SimulateClick( | 
 |         NotificationHandler::Type::EXTENSION, notification->id(), | 
 |         0 /* action_index */, std::nullopt /* reply */); | 
 |     ASSERT_TRUE(listener.WaitUntilSatisfied()); | 
 |     EXPECT_TRUE(listener.had_user_gesture()); | 
 |   } | 
 |  | 
 |   { | 
 |     ExtensionTestMessageListener listener; | 
 |     // Click event. | 
 |     display_service_tester_->SimulateClick( | 
 |         NotificationHandler::Type::EXTENSION, notification->id(), | 
 |         std::nullopt /* action_index */, std::nullopt /* reply */); | 
 |     ASSERT_TRUE(listener.WaitUntilSatisfied()); | 
 |     EXPECT_TRUE(listener.had_user_gesture()); | 
 |   } | 
 |  | 
 |   { | 
 |     ExtensionTestMessageListener listener; | 
 |     // Close event. | 
 |     display_service_tester_->RemoveNotification( | 
 |         NotificationHandler::Type::EXTENSION, notification->id(), | 
 |         true /* by_user */, false /* silent */); | 
 |     ASSERT_TRUE(listener.WaitUntilSatisfied()); | 
 |     EXPECT_TRUE(listener.had_user_gesture()); | 
 |     // Note that |notification| no longer points to valid memory. | 
 |   } | 
 |  | 
 |   ASSERT_FALSE(GetNotificationForExtension(extension)); | 
 | } | 
 | #endif  // !BUILDFLAG(IS_MAC) | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestRequireInteraction) { | 
 |   const extensions::Extension* extension = | 
 |       LoadExtensionAndWait("notifications/api/require_interaction"); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   EXPECT_TRUE(notification->never_timeout()); | 
 | } | 
 |  | 
 | #if BUILDFLAG(ENABLE_PLATFORM_APPS) | 
 | // The following tests exercise platform app behavior. | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestShouldDisplayNormal) { | 
 |   ExtensionTestMessageListener notification_created_listener("created"); | 
 |   const Extension* extension = LoadAppWithWindowState( | 
 |       "notifications/api/basic_app", WindowState::NORMAL); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |   ASSERT_TRUE(notification_created_listener.WaitUntilSatisfied()); | 
 |  | 
 |   // We start by making sure the window is actually focused. | 
 |   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( | 
 |       GetFirstAppWindow(extension->id())->GetNativeWindow())); | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   // If the app hasn't created a fullscreen window, then its notifications | 
 |   // shouldn't be displayed when a window is fullscreen. | 
 |   EXPECT_EQ(message_center::FullscreenVisibility::NONE, | 
 |             notification->fullscreen_visibility()); | 
 | } | 
 |  | 
 | // Full screen related tests don't run on Mac as native notifications full | 
 | // screen decisions are done by the OS directly. | 
 | #if !BUILDFLAG(IS_MAC) | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestShouldDisplayFullscreen) { | 
 |   ExtensionTestMessageListener notification_created_listener("created"); | 
 |   const Extension* extension = LoadAppWithWindowState( | 
 |       "notifications/api/basic_app", WindowState::FULLSCREEN); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |   ASSERT_TRUE(notification_created_listener.WaitUntilSatisfied()); | 
 |  | 
 |   // We start by making sure the window is actually focused. | 
 |   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( | 
 |       GetFirstAppWindow(extension->id())->GetNativeWindow())); | 
 |  | 
 |   ASSERT_TRUE(GetFirstAppWindow(extension->id())->IsFullscreen()) | 
 |       << "Not Fullscreen"; | 
 |   ASSERT_TRUE(GetFirstAppWindow(extension->id())->GetBaseWindow()->IsActive()) | 
 |       << "Not Active"; | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   // If the app has created a fullscreen window, then its notifications should | 
 |   // be displayed when a window is fullscreen. | 
 |   EXPECT_EQ(message_center::FullscreenVisibility::OVER_USER, | 
 |             notification->fullscreen_visibility()); | 
 | } | 
 |  | 
 | // The Fake OSX fullscreen window doesn't like drawing a second fullscreen | 
 | // window when another is visible. | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestShouldDisplayMultiFullscreen) { | 
 |   // Start a fullscreen app, and then start another fullscreen app on top of the | 
 |   // first. Notifications from the first should not be displayed because it is | 
 |   // not the app actually displaying on the screen. | 
 |   ExtensionTestMessageListener notification_created_listener("created"); | 
 |   const Extension* extension1 = LoadAppWithWindowState( | 
 |       "notifications/api/notification_on_blur", WindowState::FULLSCREEN); | 
 |   ASSERT_TRUE(extension1) << message_; | 
 |  | 
 |   ExtensionTestMessageListener window_visible_listener("visible"); | 
 |   const Extension* extension2 = LoadAppWithWindowState( | 
 |       "notifications/api/other_app", WindowState::FULLSCREEN); | 
 |   ASSERT_TRUE(extension2) << message_; | 
 |  | 
 |   ASSERT_TRUE(window_visible_listener.WaitUntilSatisfied()); | 
 |   ASSERT_TRUE(notification_created_listener.WaitUntilSatisfied()); | 
 |  | 
 |   // We start by making sure the window is actually focused. | 
 |   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( | 
 |       GetFirstAppWindow(extension2->id())->GetNativeWindow())); | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension1); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   // The first app window is superseded by the second window, so its | 
 |   // notification shouldn't be displayed. | 
 |   EXPECT_EQ(message_center::FullscreenVisibility::NONE, | 
 |             notification->fullscreen_visibility()); | 
 | } | 
 |  | 
 | // Verify that a notification is actually displayed when the app window that | 
 | // creates it is fullscreen. | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, | 
 |                        TestShouldDisplayPopupNotification) { | 
 |   ExtensionTestMessageListener notification_created_listener("created"); | 
 |   const Extension* extension = LoadAppWithWindowState( | 
 |       "notifications/api/basic_app", WindowState::FULLSCREEN); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |   ASSERT_TRUE(notification_created_listener.WaitUntilSatisfied()); | 
 |  | 
 |   // We start by making sure the window is actually focused. | 
 |   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( | 
 |       GetFirstAppWindow(extension->id())->GetNativeWindow())); | 
 |  | 
 |   ASSERT_TRUE(GetFirstAppWindow(extension->id())->IsFullscreen()) | 
 |       << "Not Fullscreen"; | 
 |   ASSERT_TRUE(GetFirstAppWindow(extension->id())->GetBaseWindow()->IsActive()) | 
 |       << "Not Active"; | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   // The extension's window is being shown and focused, so its expected that | 
 |   // the notification displays on top of it. | 
 |   EXPECT_EQ(message_center::FullscreenVisibility::OVER_USER, | 
 |             notification->fullscreen_visibility()); | 
 | } | 
 | #endif  // !BUILDFLAG(IS_MAC) | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestSmallImage) { | 
 |   ExtensionTestMessageListener notification_created_listener("created"); | 
 |   const Extension* extension = LoadAppWithWindowState( | 
 |       "notifications/api/basic_app", WindowState::NORMAL); | 
 |   ASSERT_TRUE(extension) << message_; | 
 |   ASSERT_TRUE(notification_created_listener.WaitUntilSatisfied()); | 
 |  | 
 |   message_center::Notification* notification = | 
 |       GetNotificationForExtension(extension); | 
 |   ASSERT_TRUE(notification); | 
 |  | 
 |   EXPECT_FALSE(notification->small_image().IsEmpty()); | 
 |   EXPECT_TRUE(notification->small_image_needs_additional_masking()); | 
 | } | 
 | #endif  // BUILDFLAG(ENABLE_PLATFORM_APPS) |