0

PrivacyIndicators: Add screen share icon to privacy indicators view

Add a screen share indicator to PrivacyIndicatorsTrayItemView, as well
as update it accordingly when screen sharing status changes.

We also change ScreenSecurityNotificationController to be
ScreenSecurityController since this class now also handles
non-notification related logic.

Bug: 1357853
Change-Id: Iab7c402a14db68c8d3310c1e2324057c907d2ec2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3933380
Reviewed-by: Alex Newcomer <newcomer@chromium.org>
Commit-Queue: Andre Le <leandre@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1055885}
This commit is contained in:
Andre Le
2022-10-06 18:00:02 +00:00
committed by Chromium LUCI CQ
parent 539d25dc3e
commit 619585281e
14 changed files with 386 additions and 116 deletions

@ -1618,8 +1618,8 @@ component("ash") {
"system/privacy/privacy_indicators_tray_item_view.cc",
"system/privacy/privacy_indicators_tray_item_view.h",
"system/privacy/screen_capture_observer.h",
"system/privacy/screen_security_notification_controller.cc",
"system/privacy/screen_security_notification_controller.h",
"system/privacy/screen_security_controller.cc",
"system/privacy/screen_security_controller.h",
"system/privacy/screen_share_observer.h",
"system/privacy/screen_switch_check_controller.cc",
"system/privacy/screen_switch_check_controller.h",
@ -2968,7 +2968,7 @@ test("ash_unittests") {
"system/power/video_activity_notifier_unittest.cc",
"system/privacy/privacy_indicators_controller_unittest.cc",
"system/privacy/privacy_indicators_tray_item_view_unittest.cc",
"system/privacy/screen_security_notification_controller_unittest.cc",
"system/privacy/screen_security_controller_unittest.cc",
"system/privacy_hub/camera_privacy_switch_controller_unittest.cc",
"system/privacy_hub/microphone_privacy_switch_controller_unittest.cc",
"system/progress_indicator/progress_indicator_animation_registry_unittest.cc",

@ -3988,6 +3988,10 @@ Here are some things you can try to get started.
<message name="IDS_PRIVACY_NOTIFICATION_BUTTON_APP_SETTINGS" desc="Title for the launch app button of the notification shown when an app is using the camera/microphone.">
App settings
</message>
<message name="IDS_PRIVACY_INDICATORS_VIEW_TOOLTIP" desc="Tooltip for the privacy indicators view in the status area.">
<ph name="CAMERA_AND_MICROPHONE_ACCESS_STATUS">$1<ex>You're sharing your screen</ex></ph>,
<ph name="SCREEN_SHARE_STATUS">$2<ex>Camera in use</ex></ph>
</message>
<!-- Strings for camera privacy hub switch notifications -->
<message name="IDS_PRIVACY_HUB_WANT_TO_TURN_OFF_CAMERA_NOTIFICATION_TITLE" desc="Title for a notification shown to the users when they disable camera via the hardware switch.">

@ -0,0 +1 @@
6bd63e24804bc33446d2edcdda57a66c5a89a096

@ -7,11 +7,13 @@
#include <string>
#include "ash/constants/ash_constants.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/privacy/privacy_indicators_tray_item_view.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ui/base/l10n/l10n_util.h"
@ -154,4 +156,21 @@ void UpdatePrivacyIndicatorsView(bool is_camera_used, bool is_microphone_used) {
}
}
void UpdatePrivacyIndicatorsScreenShareStatus(bool is_screen_sharing) {
if (!features::IsPrivacyIndicatorsEnabled())
return;
DCHECK(ash::Shell::HasInstance());
for (auto* root_window_controller :
ash::Shell::Get()->GetAllRootWindowControllers()) {
DCHECK(root_window_controller);
DCHECK(root_window_controller->GetStatusAreaWidget());
root_window_controller->GetStatusAreaWidget()
->unified_system_tray()
->privacy_indicators_view()
->UpdateScreenShareStatus(is_screen_sharing);
}
}
} // namespace ash

@ -69,6 +69,11 @@ void ASH_EXPORT ModifyPrivacyIndicatorsNotification(
void ASH_EXPORT UpdatePrivacyIndicatorsView(bool is_camera_used,
bool is_microphone_used);
// Update `PrivacyIndicatorsTrayItemView` screen share status across all status
// area widgets.
void ASH_EXPORT
UpdatePrivacyIndicatorsScreenShareStatus(bool is_screen_sharing);
} // namespace ash
#endif // ASH_SYSTEM_PRIVACY_PRIVACY_INDICATORS_CONTROLLER_H_

@ -14,7 +14,6 @@
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/tray/tray_item_view.h"
#include "base/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "ui/base/l10n/l10n_util.h"
@ -41,6 +40,7 @@ const int kPrivacyIndicatorsViewSpacing = 2;
const int kPrivacyIndicatorsIconSize = 16;
const int kPrivacyIndicatorsViewExpandedShorterSideSize = 24;
const int kPrivacyIndicatorsViewExpandedLongerSideSize = 50;
const int kPrivacyIndicatorsViewExpandedWithScreenShareSize = 68;
const int kPrivacyIndicatorsViewSize = 8;
constexpr auto kDwellInExpandDuration = base::Milliseconds(1000);
@ -108,19 +108,22 @@ PrivacyIndicatorsTrayItemView::PrivacyIndicatorsTrayItemView(Shelf* shelf)
layer()->SetRoundedCornerRadius(
gfx::RoundedCornersF{kPrivacyIndicatorsViewExpandedShorterSideSize / 2});
auto camera_icon = std::make_unique<views::ImageView>();
camera_icon->SetPaintToLayer();
camera_icon->layer()->SetFillsBoundsOpaquely(false);
camera_icon_ = container_view->AddChildView(std::move(camera_icon));
auto add_icon_to_container = [&container_view]() {
auto icon = std::make_unique<views::ImageView>();
icon->SetPaintToLayer();
icon->layer()->SetFillsBoundsOpaquely(false);
icon->SetVisible(false);
return container_view->AddChildView(std::move(icon));
};
auto microphone_icon = std::make_unique<views::ImageView>();
microphone_icon->SetPaintToLayer();
microphone_icon->layer()->SetFillsBoundsOpaquely(false);
microphone_icon_ = container_view->AddChildView(std::move(microphone_icon));
camera_icon_ = add_icon_to_container();
microphone_icon_ = add_icon_to_container();
screen_share_icon_ = add_icon_to_container();
AddChildView(std::move(container_view));
UpdateIcons();
TooltipTextChanged();
}
PrivacyIndicatorsTrayItemView::~PrivacyIndicatorsTrayItemView() = default;
@ -134,13 +137,23 @@ void PrivacyIndicatorsTrayItemView::Update(bool camera_is_used,
camera_is_used_ = camera_is_used;
microphone_is_used_ = microphone_is_used;
SetVisible(camera_is_used_ || microphone_is_used_);
SetVisible(camera_is_used_ || microphone_is_used_ || is_screen_sharing_);
if (!GetVisible())
return;
camera_icon_->SetVisible(camera_is_used);
microphone_icon_->SetVisible(microphone_is_used);
TooltipTextChanged();
}
void PrivacyIndicatorsTrayItemView::UpdateScreenShareStatus(
bool is_screen_sharing) {
if (is_screen_sharing_ == is_screen_sharing)
return;
is_screen_sharing_ = is_screen_sharing;
SetVisible(camera_is_used_ || microphone_is_used_ || is_screen_sharing_);
screen_share_icon_->SetVisible(is_screen_sharing_);
TooltipTextChanged();
}
@ -153,18 +166,32 @@ void PrivacyIndicatorsTrayItemView::UpdateAlignmentForShelf(Shelf* shelf) {
std::u16string PrivacyIndicatorsTrayItemView::GetTooltipText(
const gfx::Point& point) const {
auto cam_and_mic_status = std::u16string();
if (camera_is_used_ && microphone_is_used_) {
return l10n_util::GetStringUTF16(
cam_and_mic_status = l10n_util::GetStringUTF16(
IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC);
} else if (camera_is_used_) {
cam_and_mic_status =
l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA);
} else if (microphone_is_used_) {
cam_and_mic_status =
l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_MIC);
}
if (camera_is_used_)
return l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA);
auto screen_share_status =
is_screen_sharing_
? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_TITLE)
: std::u16string();
if (microphone_is_used_)
return l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_MIC);
if (cam_and_mic_status.empty())
return screen_share_status;
return std::u16string();
if (screen_share_status.empty())
return cam_and_mic_status;
return l10n_util::GetStringFUTF16(IDS_PRIVACY_INDICATORS_VIEW_TOOLTIP,
{cam_and_mic_status, screen_share_status},
/*offsets=*/nullptr);
}
void PrivacyIndicatorsTrayItemView::PerformVisibilityAnimation(bool visible) {
@ -197,13 +224,13 @@ gfx::Size PrivacyIndicatorsTrayItemView::CalculatePreferredSize() const {
case AnimationState::kExpand:
shorter_side = kPrivacyIndicatorsViewExpandedShorterSideSize;
longer_side =
kPrivacyIndicatorsViewExpandedLongerSideSize *
GetLongerSideLengthInExpandedMode() *
gfx::Tween::CalculateValue(gfx::Tween::ACCEL_20_DECEL_100,
expand_animation_->GetCurrentValue());
break;
case AnimationState::kDwellInExpand:
shorter_side = kPrivacyIndicatorsViewExpandedShorterSideSize;
longer_side = kPrivacyIndicatorsViewExpandedLongerSideSize;
longer_side = GetLongerSideLengthInExpandedMode();
break;
case AnimationState::kOnlyLongerSideShrink:
shorter_side = kPrivacyIndicatorsViewExpandedShorterSideSize;
@ -309,6 +336,9 @@ void PrivacyIndicatorsTrayItemView::UpdateIcons() {
microphone_icon_->SetImage(
gfx::CreateVectorIcon(kPrivacyIndicatorsMicrophoneIcon,
kPrivacyIndicatorsIconSize, icon_color));
screen_share_icon_->SetImage(
gfx::CreateVectorIcon(kPrivacyIndicatorsScreenShareIcon,
kPrivacyIndicatorsIconSize, icon_color));
}
void PrivacyIndicatorsTrayItemView::UpdateBoundsInset() {
@ -337,7 +367,7 @@ int PrivacyIndicatorsTrayItemView::CalculateSizeDuringShrinkAnimation(
double animation_value = gfx::Tween::CalculateValue(
gfx::Tween::ACCEL_20_DECEL_100, animation->GetCurrentValue());
int begin_size = for_longer_side
? kPrivacyIndicatorsViewExpandedLongerSideSize
? GetLongerSideLengthInExpandedMode()
: kPrivacyIndicatorsViewExpandedShorterSideSize;
// The size shrink from `begin_size` to kPrivacyIndicatorsViewSize when
@ -346,6 +376,13 @@ int PrivacyIndicatorsTrayItemView::CalculateSizeDuringShrinkAnimation(
(begin_size - kPrivacyIndicatorsViewSize) * animation_value;
}
int PrivacyIndicatorsTrayItemView::GetLongerSideLengthInExpandedMode() const {
// If all three icons are visible, the view should be longer.
return camera_is_used_ && microphone_is_used_ && is_screen_sharing_
? kPrivacyIndicatorsViewExpandedWithScreenShareSize
: kPrivacyIndicatorsViewExpandedLongerSideSize;
}
void PrivacyIndicatorsTrayItemView::EndAllAnimations() {
shorter_side_shrink_animation_->End();
longer_side_shrink_animation_->End();

@ -58,6 +58,9 @@ class ASH_EXPORT PrivacyIndicatorsTrayItemView : public TrayItemView {
// Update the view according to the state of camara/microphone access.
void Update(bool camera_is_used, bool microphone_is_used);
// Update the view according to the state of screen sharing.
void UpdateScreenShareStatus(bool is_screen_sharing);
// Update the view according to the shelf alignment.
void UpdateAlignmentForShelf(Shelf* shelf);
@ -90,6 +93,9 @@ class ASH_EXPORT PrivacyIndicatorsTrayItemView : public TrayItemView {
// shorter side.
int CalculateSizeDuringShrinkAnimation(bool for_longer_side) const;
// Calculate the length of the longer size, based on `is_screen_sharing_`.
int GetLongerSideLengthInExpandedMode() const;
// End all 3 animations contained in this class.
void EndAllAnimations();
@ -98,9 +104,11 @@ class ASH_EXPORT PrivacyIndicatorsTrayItemView : public TrayItemView {
// Owned by the views hierarchy.
views::ImageView* camera_icon_ = nullptr;
views::ImageView* microphone_icon_ = nullptr;
views::ImageView* screen_share_icon_ = nullptr;
bool camera_is_used_ = false;
bool microphone_is_used_ = false;
bool is_screen_sharing_ = false;
// Keep track the current animation state during the multi-part animation.
AnimationState animation_state_ = kIdle;

@ -40,6 +40,21 @@ int GetExpectedSizeInShrinkAnimation(bool for_longer_side, double progress) {
(begin_size - kPrivacyIndicatorsViewSize) * animation_value;
}
// Get the expected tooltip text, given the string for camera/mic access and
// screen share.
std::u16string GetExpectedTooltipText(std::u16string cam_mic_status,
std::u16string screen_share_status) {
if (cam_mic_status.empty())
return screen_share_status;
if (screen_share_status.empty())
return cam_mic_status;
return l10n_util::GetStringFUTF16(IDS_PRIVACY_INDICATORS_VIEW_TOOLTIP,
{cam_mic_status, screen_share_status},
/*offsets=*/nullptr);
}
} // namespace
namespace ash {
@ -94,6 +109,9 @@ class PrivacyIndicatorsTrayItemViewTest : public AshTestBase {
views::ImageView* microphone_icon() {
return privacy_indicators_view_->microphone_icon_;
}
views::ImageView* screen_share_icon() {
return privacy_indicators_view_->screen_share_icon_;
}
gfx::LinearAnimation* expand_animation() {
return privacy_indicators_view_->expand_animation_.get();
@ -143,28 +161,78 @@ TEST_F(PrivacyIndicatorsTrayItemViewTest, IconsVisibility) {
EXPECT_FALSE(privacy_indicators_view()->GetVisible());
}
TEST_F(PrivacyIndicatorsTrayItemViewTest, ScreenShareIconsVisibility) {
EXPECT_FALSE(privacy_indicators_view()->GetVisible());
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/true);
EXPECT_TRUE(privacy_indicators_view()->GetVisible());
EXPECT_TRUE(screen_share_icon()->GetVisible());
EXPECT_FALSE(camera_icon()->GetVisible());
EXPECT_FALSE(microphone_icon()->GetVisible());
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/false);
EXPECT_FALSE(privacy_indicators_view()->GetVisible());
// Test screen share showing up with other icons.
privacy_indicators_view()->Update(/*camera_is_used=*/false,
/*microphone_is_used=*/true);
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/true);
EXPECT_TRUE(privacy_indicators_view()->GetVisible());
EXPECT_FALSE(camera_icon()->GetVisible());
EXPECT_TRUE(microphone_icon()->GetVisible());
EXPECT_TRUE(screen_share_icon()->GetVisible());
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/false);
EXPECT_TRUE(privacy_indicators_view()->GetVisible());
EXPECT_FALSE(camera_icon()->GetVisible());
EXPECT_TRUE(microphone_icon()->GetVisible());
EXPECT_FALSE(screen_share_icon()->GetVisible());
}
TEST_F(PrivacyIndicatorsTrayItemViewTest, TooltipText) {
EXPECT_EQ(std::u16string(), GetTooltipText());
EXPECT_EQ(GetExpectedTooltipText(/*cam_mic_status=*/std::u16string(),
/*screen_share_status=*/std::u16string()),
GetTooltipText());
privacy_indicators_view()->Update(/*camera_is_used=*/true,
/*microphone_is_used=*/false);
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA),
EXPECT_EQ(GetExpectedTooltipText(/*cam_mic_status=*/l10n_util::GetStringUTF16(
IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA),
/*screen_share_status=*/std::u16string()),
GetTooltipText());
privacy_indicators_view()->Update(/*camera_is_used=*/false,
/*microphone_is_used=*/true);
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_MIC),
EXPECT_EQ(GetExpectedTooltipText(/*cam_mic_status=*/l10n_util::GetStringUTF16(
IDS_PRIVACY_NOTIFICATION_TITLE_MIC),
/*screen_share_status=*/std::u16string()),
GetTooltipText());
privacy_indicators_view()->Update(/*camera_is_used=*/true,
/*microphone_is_used=*/true);
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC),
GetExpectedTooltipText(/*cam_mic_status=*/l10n_util::GetStringUTF16(
IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC),
/*screen_share_status=*/std::u16string()),
GetTooltipText());
privacy_indicators_view()->Update(/*camera_is_used=*/false,
/*microphone_is_used=*/false);
EXPECT_EQ(std::u16string(), GetTooltipText());
EXPECT_EQ(GetExpectedTooltipText(/*cam_mic_status=*/std::u16string(),
/*screen_share_status=*/std::u16string()),
GetTooltipText());
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/true);
EXPECT_EQ(GetExpectedTooltipText(
/*cam_mic_status=*/std::u16string(),
/*screen_share_status=*/l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_SCREEN_SHARE_TITLE)),
GetTooltipText());
}
TEST_F(PrivacyIndicatorsTrayItemViewTest, ShelfAlignmentChanged) {
@ -322,4 +390,36 @@ TEST_F(PrivacyIndicatorsTrayItemViewTest, SideShelfVisibilityAnimation) {
privacy_indicators_view()->GetPreferredSize().height());
}
TEST_F(PrivacyIndicatorsTrayItemViewTest, StateChangeDuringAnimation) {
SetViewVisibleWithAnimation();
double progress = 0.5;
// Firstly, expand animation will be performed.
AnimateToValue(expand_animation(), progress);
// Update state in mid animation, shouldn't crash anything.
privacy_indicators_view()->Update(/*camera_is_used=*/true,
/*microphone_is_used=*/false);
expand_animation()->End();
// After that shrink animations will be started.
longer_side_shrink_animation()->Start();
AnimateToValue(longer_side_shrink_animation(), progress);
// Update the state again, no crash expected.
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/true);
shorter_side_shrink_animation()->Start();
AnimateToValue(shorter_side_shrink_animation(), progress);
// The view should become invisible immediately after setting these states.
privacy_indicators_view()->Update(/*camera_is_used=*/false,
/*microphone_is_used=*/false);
privacy_indicators_view()->UpdateScreenShareStatus(
/*is_screen_sharing=*/false);
EXPECT_FALSE(privacy_indicators_view()->GetVisible());
}
} // namespace ash

@ -2,7 +2,7 @@
// 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_notification_controller.h"
#include "ash/system/privacy/screen_security_controller.h"
#include "ash/constants/ash_constants.h"
#include "ash/constants/ash_features.h"
@ -11,6 +11,7 @@
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/privacy/privacy_indicators_controller.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "base/bind.h"
#include "base/metrics/user_metrics.h"
@ -32,21 +33,20 @@ const char kScreenShareNotificationId[] = "chrome://screen/share";
const char kNotifierScreenCapture[] = "ash.screen-capture";
const char kNotifierScreenShare[] = "ash.screen-share";
ScreenSecurityNotificationController::ScreenSecurityNotificationController() {
ScreenSecurityController::ScreenSecurityController() {
Shell::Get()->AddShellObserver(this);
Shell::Get()->system_tray_notifier()->AddScreenCaptureObserver(this);
Shell::Get()->system_tray_notifier()->AddScreenShareObserver(this);
}
ScreenSecurityNotificationController::~ScreenSecurityNotificationController() {
ScreenSecurityController::~ScreenSecurityController() {
Shell::Get()->system_tray_notifier()->RemoveScreenShareObserver(this);
Shell::Get()->system_tray_notifier()->RemoveScreenCaptureObserver(this);
Shell::Get()->RemoveShellObserver(this);
}
void ScreenSecurityNotificationController::CreateNotification(
const std::u16string& message,
bool is_capture) {
void ScreenSecurityController::CreateNotification(const std::u16string& message,
bool is_capture) {
message_center::RichNotificationData data;
data.buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16(
is_capture ? IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP
@ -62,7 +62,7 @@ void ScreenSecurityNotificationController::CreateNotification(
auto delegate =
base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
base::BindRepeating(
[](base::WeakPtr<ScreenSecurityNotificationController> controller,
[](base::WeakPtr<ScreenSecurityController> controller,
bool is_capture, absl::optional<int> button_index) {
if (!button_index)
return;
@ -125,7 +125,7 @@ void ScreenSecurityNotificationController::CreateNotification(
std::move(notification));
}
void ScreenSecurityNotificationController::StopAllSessions(bool is_capture) {
void ScreenSecurityController::StopAllSessions(bool is_capture) {
message_center::MessageCenter::Get()->RemoveNotification(
is_capture ? kScreenCaptureNotificationId : kScreenShareNotificationId,
false /* by_user */);
@ -141,12 +141,12 @@ void ScreenSecurityNotificationController::StopAllSessions(bool is_capture) {
change_source_callback_.Reset();
}
void ScreenSecurityNotificationController::ChangeSource() {
void ScreenSecurityController::ChangeSource() {
if (change_source_callback_ && capture_stop_callbacks_.size() == 1)
change_source_callback_.Run();
}
void ScreenSecurityNotificationController::OnScreenCaptureStart(
void ScreenSecurityController::OnScreenCaptureStart(
const base::RepeatingClosure& stop_callback,
const base::RepeatingClosure& source_callback,
const std::u16string& screen_capture_status) {
@ -166,11 +166,11 @@ void ScreenSecurityNotificationController::OnScreenCaptureStart(
CreateNotification(screen_capture_status, true /* is_capture */);
}
void ScreenSecurityNotificationController::OnScreenCaptureStop() {
void ScreenSecurityController::OnScreenCaptureStop() {
StopAllSessions(true /* is_capture */);
}
void ScreenSecurityNotificationController::OnScreenShareStart(
void ScreenSecurityController::OnScreenShareStart(
const base::RepeatingClosure& stop_callback,
const std::u16string& helper_name) {
share_stop_callbacks_.emplace_back(std::move(stop_callback));
@ -185,14 +185,19 @@ void ScreenSecurityNotificationController::OnScreenShareStart(
}
CreateNotification(help_label_text, false /* is_capture */);
if (features::IsPrivacyIndicatorsEnabled())
UpdatePrivacyIndicatorsScreenShareStatus(/*is_screen_sharing=*/true);
}
void ScreenSecurityNotificationController::OnScreenShareStop() {
void ScreenSecurityController::OnScreenShareStop() {
StopAllSessions(false /* is_capture */);
if (features::IsPrivacyIndicatorsEnabled())
UpdatePrivacyIndicatorsScreenShareStatus(/*is_screen_sharing=*/false);
}
void ScreenSecurityNotificationController::OnCastingSessionStartedOrStopped(
bool started) {
void ScreenSecurityController::OnCastingSessionStartedOrStopped(bool started) {
is_casting_ = started;
}

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_PRIVACY_SCREEN_SECURITY_NOTIFICATION_CONTROLLER_H_
#define ASH_SYSTEM_PRIVACY_SCREEN_SECURITY_NOTIFICATION_CONTROLLER_H_
#ifndef ASH_SYSTEM_PRIVACY_SCREEN_SECURITY_CONTROLLER_H_
#define ASH_SYSTEM_PRIVACY_SCREEN_SECURITY_CONTROLLER_H_
#include <string>
#include <vector>
@ -21,19 +21,16 @@ extern ASH_EXPORT const char kNotifierScreenCapture[];
extern ASH_EXPORT const char kNotifierScreenShare[];
// Controller class to manage screen security notifications.
class ASH_EXPORT ScreenSecurityNotificationController
: public ScreenCaptureObserver,
public ScreenShareObserver,
public ShellObserver {
class ASH_EXPORT ScreenSecurityController : public ScreenCaptureObserver,
public ScreenShareObserver,
public ShellObserver {
public:
ScreenSecurityNotificationController();
ScreenSecurityController();
ScreenSecurityNotificationController(
const ScreenSecurityNotificationController&) = delete;
ScreenSecurityNotificationController& operator=(
const ScreenSecurityNotificationController&) = delete;
ScreenSecurityController(const ScreenSecurityController&) = delete;
ScreenSecurityController& operator=(const ScreenSecurityController&) = delete;
~ScreenSecurityNotificationController() override;
~ScreenSecurityController() override;
private:
void CreateNotification(const std::u16string& message, bool is_capture);
@ -69,10 +66,9 @@ class ASH_EXPORT ScreenSecurityNotificationController
std::vector<base::OnceClosure> share_stop_callbacks_;
base::RepeatingClosure change_source_callback_;
base::WeakPtrFactory<ScreenSecurityNotificationController> weak_ptr_factory_{
this};
base::WeakPtrFactory<ScreenSecurityController> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_SYSTEM_PRIVACY_SCREEN_SECURITY_NOTIFICATION_CONTROLLER_H_
#endif // ASH_SYSTEM_PRIVACY_SCREEN_SECURITY_CONTROLLER_H_

@ -0,0 +1,150 @@
// 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/privacy/privacy_indicators_tray_item_view.h"
#include "ash/system/status_area_widget.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/callback.h"
#include "base/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()) {
EXPECT_EQ(root_window_controller->GetStatusAreaWidget()
->unified_system_tray()
->privacy_indicators_view()
->GetVisible(),
visible);
}
}
} // namespace
class ScreenSecurityControllerTest : public AshTestBase,
public testing::WithParamInterface<bool> {
public:
ScreenSecurityControllerTest() = default;
ScreenSecurityControllerTest(const ScreenSecurityControllerTest&) = delete;
ScreenSecurityControllerTest& operator=(const ScreenSecurityControllerTest&) =
delete;
~ScreenSecurityControllerTest() override = default;
// AppAccessNotifierBaseTest:
void SetUp() override {
scoped_feature_list_.InitWithFeatureState(
features::kPrivacyIndicators, IsPrivacyIndicatorsFeatureEnabled());
AshTestBase::SetUp();
}
bool IsPrivacyIndicatorsFeatureEnabled() const { return GetParam(); }
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
All,
ScreenSecurityControllerTest,
/*IsPrivacyIndicatorsFeatureEnabled()=*/::testing::Bool());
TEST_P(ScreenSecurityControllerTest, ShowScreenCaptureNotification) {
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStart(
base::DoNothing(), base::RepeatingClosure(), std::u16string());
EXPECT_TRUE(FindNotification(kScreenCaptureNotificationId));
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
EXPECT_FALSE(FindNotification(kScreenCaptureNotificationId));
}
TEST_P(ScreenSecurityControllerTest, ShowScreenShareNotification) {
Shell::Get()->system_tray_notifier()->NotifyScreenShareStart(
base::DoNothing(), std::u16string());
EXPECT_TRUE(FindNotification(kScreenShareNotificationId));
Shell::Get()->system_tray_notifier()->NotifyScreenShareStop();
EXPECT_FALSE(FindNotification(kScreenShareNotificationId));
}
TEST_P(ScreenSecurityControllerTest,
DoNotShowScreenCaptureNotificationWhenCasting) {
Shell::Get()->OnCastingSessionStartedOrStopped(true /* started */);
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStart(
base::DoNothing(), base::RepeatingClosure(), std::u16string());
EXPECT_FALSE(FindNotification(kScreenCaptureNotificationId));
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
Shell::Get()->OnCastingSessionStartedOrStopped(false /* started */);
EXPECT_FALSE(FindNotification(kScreenCaptureNotificationId));
}
class PrivacyIndicatorsScreenSecurityTest : public AshTestBase {
public:
PrivacyIndicatorsScreenSecurityTest() = default;
PrivacyIndicatorsScreenSecurityTest(
const PrivacyIndicatorsScreenSecurityTest&) = delete;
PrivacyIndicatorsScreenSecurityTest& operator=(
const PrivacyIndicatorsScreenSecurityTest&) = delete;
~PrivacyIndicatorsScreenSecurityTest() override = default;
// AshTestBase:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(features::kPrivacyIndicators);
AshTestBase::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(PrivacyIndicatorsScreenSecurityTest, ScreenShareNotification) {
Shell::Get()->system_tray_notifier()->NotifyScreenShareStart(
base::DoNothing(), std::u16string());
auto* notification = FindNotification(kScreenShareNotificationId);
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(PrivacyIndicatorsScreenSecurityTest, TrayItemIndicator) {
// Make sure the indicator shows up on multiple displays.
UpdateDisplay("400x300,400x300,400x300,400x300");
ExpectPrivacyIndicatorsVisible(/*visible=*/false);
Shell::Get()->system_tray_notifier()->NotifyScreenShareStart(
base::DoNothing(), std::u16string());
ExpectPrivacyIndicatorsVisible(/*visible=*/true);
Shell::Get()->system_tray_notifier()->NotifyScreenShareStop();
ExpectPrivacyIndicatorsVisible(/*visible=*/false);
}
} // namespace ash

@ -1,54 +0,0 @@
// 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_notification_controller.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/test/ash_test_base.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "ui/message_center/message_center.h"
namespace ash {
using ScreenSecurityNotificationControllerTest = AshTestBase;
namespace {
message_center::Notification* FindNotification(const std::string& id) {
return message_center::MessageCenter::Get()->FindVisibleNotificationById(id);
}
} // namespace
TEST_F(ScreenSecurityNotificationControllerTest,
ShowScreenCaptureNotification) {
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStart(
base::DoNothing(), base::RepeatingClosure(), std::u16string());
EXPECT_TRUE(FindNotification(kScreenCaptureNotificationId));
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
EXPECT_FALSE(FindNotification(kScreenCaptureNotificationId));
}
TEST_F(ScreenSecurityNotificationControllerTest, ShowScreenShareNotification) {
Shell::Get()->system_tray_notifier()->NotifyScreenShareStart(
base::DoNothing(), std::u16string());
EXPECT_TRUE(FindNotification(kScreenShareNotificationId));
Shell::Get()->system_tray_notifier()->NotifyScreenShareStop();
EXPECT_FALSE(FindNotification(kScreenShareNotificationId));
}
TEST_F(ScreenSecurityNotificationControllerTest,
DoNotShowScreenCaptureNotificationWhenCasting) {
Shell::Get()->OnCastingSessionStartedOrStopped(true /* started */);
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStart(
base::DoNothing(), base::RepeatingClosure(), std::u16string());
EXPECT_FALSE(FindNotification(kScreenCaptureNotificationId));
Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
Shell::Get()->OnCastingSessionStartedOrStopped(false /* started */);
EXPECT_FALSE(FindNotification(kScreenCaptureNotificationId));
}
} // namespace ash

@ -14,7 +14,7 @@
#include "ash/system/network/managed_sim_lock_notifier.h"
#include "ash/system/network/wifi_toggle_notification_controller.h"
#include "ash/system/power/power_notification_controller.h"
#include "ash/system/privacy/screen_security_notification_controller.h"
#include "ash/system/privacy/screen_security_controller.h"
#include "ash/system/session/session_limit_notification_controller.h"
#include "ash/system/tracing_notification_controller.h"
#include "ash/system/update/update_notification_controller.h"
@ -31,8 +31,7 @@ SystemNotificationController::SystemNotificationController()
std::make_unique<GestureEducationNotificationController>()),
power_(std::make_unique<PowerNotificationController>(
message_center::MessageCenter::Get())),
screen_security_(
std::make_unique<ScreenSecurityNotificationController>()),
screen_security_(std::make_unique<ScreenSecurityController>()),
session_limit_(std::make_unique<SessionLimitNotificationController>()),
tracing_(std::make_unique<TracingNotificationController>()),
update_(std::make_unique<UpdateNotificationController>()),

@ -18,7 +18,7 @@ class CellularSetupNotifier;
class ManagedSimLockNotifier;
class MicrophoneMuteNotificationController;
class PowerNotificationController;
class ScreenSecurityNotificationController;
class ScreenSecurityController;
class SessionLimitNotificationController;
class TracingNotificationController;
class UpdateNotificationController;
@ -50,7 +50,7 @@ class SystemNotificationController {
std::unique_ptr<ManagedSimLockNotifier> managed_sim_lock_notifier_;
std::unique_ptr<MicrophoneMuteNotificationController> microphone_mute_;
const std::unique_ptr<PowerNotificationController> power_;
const std::unique_ptr<ScreenSecurityNotificationController> screen_security_;
const std::unique_ptr<ScreenSecurityController> screen_security_;
const std::unique_ptr<SessionLimitNotificationController> session_limit_;
const std::unique_ptr<TracingNotificationController> tracing_;
const std::unique_ptr<UpdateNotificationController> update_;