chromium/ash/system/privacy/screen_security_controller_unittest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/system/privacy/screen_security_controller.h"

#include "ash/constants/ash_constants.h"
#include "ash/constants/ash_features.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/system/notification_center/notification_center_tray.h"
#include "ash/system/privacy/privacy_indicators_tray_item_view.h"
#include "ash/system/privacy/screen_security_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/system_notification_controller.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/test/ash_test_base.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/test/scoped_feature_list.h"
#include "ui/color/color_id.h"
#include "ui/message_center/message_center.h"

namespace ash {

namespace {

message_center::Notification* FindNotification(const std::string& id) {
  return message_center::MessageCenter::Get()->FindVisibleNotificationById(id);
}

// Check the visibility of privacy indicators in all displays.
void ExpectPrivacyIndicatorsVisible(bool visible) {
  for (ash::RootWindowController* root_window_controller :
       ash::Shell::Get()->GetAllRootWindowControllers()) {
    auto* privacy_indicators_view =
        root_window_controller->GetStatusAreaWidget()
            ->notification_center_tray()
            ->privacy_indicators_view();

    EXPECT_EQ(privacy_indicators_view->GetVisible(), visible);
  }
}

}  // namespace

class ScreenSecurityControllerTest : public AshTestBase {
 public:
  ScreenSecurityControllerTest() = default;
  ScreenSecurityControllerTest(const ScreenSecurityControllerTest&) = delete;
  ScreenSecurityControllerTest& operator=(const ScreenSecurityControllerTest&) =
      delete;
  ~ScreenSecurityControllerTest() override = default;

  // AppAccessNotifierBaseTest:
  void SetUp() override {
    // This class is used only when video conference feature is not available.
    scoped_feature_list_.InitAndDisableFeature(
        features::kFeatureManagementVideoConference);
    AshTestBase::SetUp();
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

// Tests that `StopAllSessions()` is working properly with both params.
TEST_F(ScreenSecurityControllerTest, StopAllSessions) {
  bool stop_callback_called = false;

  auto stop_callback = base::BindRepeating(
      [](bool* stop_callback_called) { *stop_callback_called = true; },
      base::Unretained(&stop_callback_called));
  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStart(
      stop_callback, base::RepeatingClosure(), std::u16string());

  Shell::Get()
      ->system_notification_controller()
      ->screen_security_controller()
      ->StopAllSessions(/*is_screen_access=*/true);
  EXPECT_TRUE(stop_callback_called);

  stop_callback_called = false;
  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStart(
      stop_callback);

  Shell::Get()
      ->system_notification_controller()
      ->screen_security_controller()
      ->StopAllSessions(/*is_screen_access=*/false);
  EXPECT_TRUE(stop_callback_called);
}

TEST_F(ScreenSecurityControllerTest, ShowScreenCaptureNotification) {
  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStart(
      base::DoNothing(), base::RepeatingClosure(), std::u16string());
  EXPECT_TRUE(FindNotification(kScreenAccessNotificationId));

  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStop();

  EXPECT_FALSE(FindNotification(kScreenAccessNotificationId));
}

TEST_F(ScreenSecurityControllerTest, ShowScreenShareNotification) {
  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStart(
      base::DoNothing());

  EXPECT_TRUE(FindNotification(kRemotingScreenShareNotificationId));

  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStop();

  EXPECT_FALSE(FindNotification(kRemotingScreenShareNotificationId));
}

// Tests that `NotifyRemotingScreenShareStop()` does not crash if called with no
// notification with VideoConference enabled and disabled.
TEST_F(ScreenSecurityControllerTest, NotifyScreenShareStopNoNotification) {
  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStop();

  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      features::kFeatureManagementVideoConference);
  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStop();
}

// Tests that screen share notifications do not show when VideoConference is
// enabled.
TEST_F(ScreenSecurityControllerTest,
       NoScreenShareNotificationWithVideoConference) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      features::kFeatureManagementVideoConference);

  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStart(
      base::DoNothing());

  EXPECT_FALSE(FindNotification(kRemotingScreenShareNotificationId));
}

// Tests that calling `NotifyScreenAccessStop()` does not crash if called with
// no notification with VideoConference enabled and disabled.
TEST_F(ScreenSecurityControllerTest, NotifyScreenCaptureStopNoNotification) {
  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStop();

  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      features::kFeatureManagementVideoConference);
  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStop();
}

// Tests that screen capture notifications do not show with video conference
// enabled.
TEST_F(ScreenSecurityControllerTest,
       ScreenCaptureShowsNotificationWithVideoConference) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      features::kFeatureManagementVideoConference);

  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStart(
      base::DoNothing(), base::RepeatingClosure(), std::u16string());

  EXPECT_FALSE(FindNotification(kScreenAccessNotificationId));
}

TEST_F(ScreenSecurityControllerTest,
       DoNotShowScreenCaptureNotificationWhenCasting) {
  Shell::Get()->OnCastingSessionStartedOrStopped(true /* started */);
  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStart(
      base::DoNothing(), base::RepeatingClosure(), std::u16string());
  EXPECT_FALSE(FindNotification(kScreenAccessNotificationId));

  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStop();
  Shell::Get()->OnCastingSessionStartedOrStopped(false /* started */);
  EXPECT_FALSE(FindNotification(kScreenAccessNotificationId));
}

// Tests that the screen share notification is created with proper metadata when
// the `SystemTrayNotifier` notifies observers of screen share start.
TEST_F(ScreenSecurityControllerTest, ScreenShareNotification) {
  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStart(
      base::DoNothing());

  auto* notification = FindNotification(kRemotingScreenShareNotificationId);
  EXPECT_TRUE(notification);

  // Notification should have the correct notifier id so that it will be grouped
  // with other privacy indicators notification.
  EXPECT_EQ(kPrivacyIndicatorsNotifierId, notification->notifier_id().id);

  EXPECT_EQ(ui::kColorAshPrivacyIndicatorsBackground,
            notification->accent_color_id());
}

TEST_F(ScreenSecurityControllerTest, ScreenShareTrayItemIndicator) {
  // Make sure the indicator shows up on multiple displays.
  UpdateDisplay("400x300,400x300,400x300,400x300");

  ExpectPrivacyIndicatorsVisible(/*visible=*/false);

  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStart(
      base::DoNothing(), base::DoNothing(), std::u16string());
  ExpectPrivacyIndicatorsVisible(/*visible=*/true);

  Shell::Get()->system_tray_notifier()->NotifyScreenAccessStop();
  ExpectPrivacyIndicatorsVisible(/*visible=*/false);
}

// Tests that the privacy indicator shows up on multiple displays, if they
// displays exist before screen share starts.
TEST_F(ScreenSecurityControllerTest, RemotingScreenShareTrayItemIndicator) {
  // Make sure the indicator shows up on multiple displays.
  UpdateDisplay("400x300,400x300,400x300,400x300");

  ExpectPrivacyIndicatorsVisible(/*visible=*/false);

  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStart(
      base::DoNothing());
  ExpectPrivacyIndicatorsVisible(/*visible=*/true);

  Shell::Get()->system_tray_notifier()->NotifyRemotingScreenShareStop();
  ExpectPrivacyIndicatorsVisible(/*visible=*/false);
}

}  // namespace ash