[Privacy Hub] Refactor software switch notification [2/2]
This is the second in a series of two CLs that re-implements the Privacy
Hub software switch notifications. Camera software switch notification,
microphone software switch notification and the combined notification
will be represented by a same notification object, thus the three
notifications will have same notification ID. This makes sure two or
more of the three notifications can not be in visible simultaneously.
Bug: b:267769814
Change-Id: I550bf06204c5525434678394e80156947ad77c8b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4272268
Reviewed-by: Christoph Schlosser <cschlosser@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Md Shahadat Hossain Shahin <shahinmd@google.com>
Cr-Commit-Position: refs/heads/main@{#1113454}
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller.cc b/ash/system/privacy_hub/camera_privacy_switch_controller.cc
index e019f6b..4dc1c7e9 100644
--- a/ash/system/privacy_hub/camera_privacy_switch_controller.cc
+++ b/ash/system/privacy_hub/camera_privacy_switch_controller.cc
@@ -65,7 +65,7 @@
PrivacyHubNotificationDescriptor{
SensorDisabledNotificationDelegate::SensorSet{},
IDS_PRIVACY_HUB_WANT_TO_TURN_OFF_CAMERA_NOTIFICATION_TITLE,
- IDS_PRIVACY_HUB_TURN_OFF_CAMERA_ACTION_BUTTON,
+ std::vector<int>{IDS_PRIVACY_HUB_TURN_OFF_CAMERA_ACTION_BUTTON},
std::vector<int>{
IDS_PRIVACY_HUB_WANT_TO_TURN_OFF_CAMERA_NOTIFICATION_MESSAGE},
base::MakeRefCounted<PrivacyHubNotificationClickDelegate>(
@@ -130,11 +130,11 @@
if (pref_val == CameraSWPrivacySwitchSetting::kDisabled) {
camera_used_while_deactivated_ = true;
- GetPrivacyHubNotificationController()->ShowSensorDisabledNotification(
+ GetPrivacyHubNotificationController()->ShowSoftwareSwitchNotification(
SensorDisabledNotificationDelegate::Sensor::kCamera);
} else {
camera_used_while_deactivated_ = false;
- GetPrivacyHubNotificationController()->RemoveSensorDisabledNotification(
+ GetPrivacyHubNotificationController()->RemoveSoftwareSwitchNotification(
SensorDisabledNotificationDelegate::Sensor::kCamera);
}
}
@@ -221,14 +221,14 @@
if (active_applications_using_camera_count_ == 0 &&
camera_used_while_deactivated_) {
camera_used_while_deactivated_ = false;
- GetPrivacyHubNotificationController()->RemoveSensorDisabledNotification(
+ GetPrivacyHubNotificationController()->RemoveSoftwareSwitchNotification(
SensorDisabledNotificationDelegate::Sensor::kCamera);
} else if (application_added) {
camera_used_while_deactivated_ = true;
- GetPrivacyHubNotificationController()->ShowSensorDisabledNotification(
+ GetPrivacyHubNotificationController()->ShowSoftwareSwitchNotification(
SensorDisabledNotificationDelegate::Sensor::kCamera);
} else {
- GetPrivacyHubNotificationController()->UpdateSensorDisabledNotification(
+ GetPrivacyHubNotificationController()->UpdateSoftwareSwitchNotification(
SensorDisabledNotificationDelegate::Sensor::kCamera);
}
}
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller.h b/ash/system/privacy_hub/camera_privacy_switch_controller.h
index 1824fba..681f210 100644
--- a/ash/system/privacy_hub/camera_privacy_switch_controller.h
+++ b/ash/system/privacy_hub/camera_privacy_switch_controller.h
@@ -17,10 +17,6 @@
namespace ash {
-// The ID for a notification shown when the user tries to use a camera while the
-// camera is disabled in Privacy Hub.
-inline constexpr char kPrivacyHubCameraOffNotificationId[] =
- "ash.media.privacy_hub.activity_with_disabled_camera";
// The ID for a notification shown when the user enables camera via a HW switch
// but it is still disabled in PrivacyHub.
inline constexpr char
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc
index 2ef9bbcd..e584f805 100644
--- a/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc
+++ b/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc
@@ -14,6 +14,7 @@
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/privacy_hub/privacy_hub_controller.h"
#include "ash/system/privacy_hub/privacy_hub_metrics.h"
+#include "ash/system/privacy_hub/privacy_hub_notification_controller.h"
#include "ash/test/ash_test_base.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
@@ -362,12 +363,14 @@
message_center::MessageCenter* const message_center =
message_center::MessageCenter::Get();
ASSERT_TRUE(message_center);
- ASSERT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ ASSERT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
// An application starts accessing the camera.
controller_->ActiveApplicationsChanged(/*application_added=*/true);
// A notification should be fired.
- EXPECT_TRUE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_TRUE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
EXPECT_FALSE(GetUserPref());
EXPECT_EQ(histogram_tester_.GetBucketCount(
@@ -376,10 +379,11 @@
true),
0);
// Enabling camera via clicking on the button should clear the notification
- message_center->ClickOnNotificationButton(kPrivacyHubCameraOffNotificationId,
- 0);
+ message_center->ClickOnNotificationButton(
+ PrivacyHubNotificationController::kCombinedNotificationId, 0);
EXPECT_TRUE(GetUserPref());
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
EXPECT_EQ(histogram_tester_.GetBucketCount(
privacy_hub_metrics::
kPrivacyHubCameraEnabledFromNotificationHistogram,
@@ -394,21 +398,25 @@
message_center::MessageCenter* const message_center =
message_center::MessageCenter::Get();
ASSERT_TRUE(message_center);
- ASSERT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ ASSERT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
// An application starts accessing the camera.
controller_->ActiveApplicationsChanged(/*application_added=*/true);
// A notification should be fired.
- EXPECT_TRUE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_TRUE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
EXPECT_FALSE(GetUserPref());
// Enabling camera via clicking on the body should open the privacy hub
// settings page.
- message_center->ClickOnNotification(kPrivacyHubCameraOffNotificationId);
+ message_center->ClickOnNotification(
+ PrivacyHubNotificationController::kCombinedNotificationId);
// The user pref should not be changed.
EXPECT_FALSE(GetUserPref());
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
SetUserPref(true);
@@ -440,19 +448,23 @@
TEST_F(PrivacyHubCameraControllerTests,
CameraOffNotificationRemoveViaUserPref) {
SetUserPref(false);
- ASSERT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ ASSERT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
// An application starts accessing the camera.
controller_->ActiveApplicationsChanged(/*application_added=*/true);
// A notification should be fired.
- EXPECT_TRUE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_TRUE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
EXPECT_FALSE(GetUserPref());
// Enabling camera via the user pref should clear the notification
SetUserPref(true);
EXPECT_TRUE(GetUserPref());
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ WaitUntilNotificationRemoved(
+ PrivacyHubNotificationController::kCombinedNotificationId);
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
}
TEST_F(PrivacyHubCameraControllerTests, InSessionSwitchNotification) {
@@ -460,7 +472,8 @@
message_center::MessageCenter* const message_center =
message_center::MessageCenter::Get();
ASSERT_TRUE(message_center);
- message_center->RemoveNotification(kPrivacyHubCameraOffNotificationId, false);
+ message_center->RemoveNotification(
+ PrivacyHubNotificationController::kCombinedNotificationId, false);
// An application starts accessing the camera.
controller_->ActiveApplicationsChanged(/*application_added=*/true);
@@ -468,7 +481,8 @@
SetUserPref(false);
// A notification should be fired.
- EXPECT_TRUE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_TRUE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
EXPECT_FALSE(GetUserPref());
EXPECT_EQ(histogram_tester_.GetBucketCount(
@@ -477,10 +491,11 @@
true),
0);
// Enabling camera via clicking on the button should clear the notification
- message_center->ClickOnNotificationButton(kPrivacyHubCameraOffNotificationId,
- 0);
+ message_center->ClickOnNotificationButton(
+ PrivacyHubNotificationController::kCombinedNotificationId, 0);
EXPECT_TRUE(GetUserPref());
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
EXPECT_EQ(histogram_tester_.GetBucketCount(
privacy_hub_metrics::
kPrivacyHubCameraEnabledFromNotificationHistogram,
@@ -488,14 +503,15 @@
1);
}
-// Tests if the notification `kPrivacyHubCameraOffNotificationId` is removed
-// when the number of apps accessing the camera becomes 0.
+// Tests if camera software switch notification is removed when the number of
+// apps accessing the camera becomes 0.
TEST_F(PrivacyHubCameraControllerTests,
NotificationRemovedWhenNoActiveApplication) {
SetUserPref(true);
// The notification should not be in the message center initially.
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
// This is the effect of an application starting to access the camera.
controller_->ActiveApplicationsChanged(/*application_added=*/true);
@@ -503,32 +519,38 @@
// Disabling camera using the software switch.
SetUserPref(false);
- // Notification `kPrivacyHubCameraOffNotificationId` should pop up.
- EXPECT_TRUE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ // Notification `PrivacyHubNotificationController::kCombinedNotificationId`
+ // should pop up.
+ EXPECT_TRUE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
// The only active application stops accessing the camera the camera.
controller_->ActiveApplicationsChanged(/*application_added=*/false);
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
+ WaitUntilNotificationRemoved(
+ PrivacyHubNotificationController::kCombinedNotificationId);
- // Existing notification `kPrivacyHubCameraOffNotificationId` should be
+ // Existing notification
+ // `PrivacyHubNotificationController::kCombinedNotificationId` should be
// removed as the number of active applications is 0 now.
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
}
// Tests if the camera software switch notification contains proper text.
TEST_F(PrivacyHubCameraControllerTests, NotificationText) {
// Disabling camera using the software switch.
SetUserPref(false);
- EXPECT_FALSE(FindNotificationById(kPrivacyHubCameraOffNotificationId));
+ EXPECT_FALSE(FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId));
// Launch app1 that's accessing camera, a notification should be displayed
// with the application name in the notification body.
const std::u16string app1 = u"app1";
LaunchAppAccessingCamera(app1);
- message_center::Notification* notification =
- FindNotificationById(kPrivacyHubCameraOffNotificationId);
+ message_center::Notification* notification = FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId);
ASSERT_TRUE(notification);
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_TITLE),
@@ -545,7 +567,8 @@
const std::u16string app2 = u"app2";
LaunchAppAccessingCamera(app2);
- notification = FindNotificationById(kPrivacyHubCameraOffNotificationId);
+ notification = FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId);
ASSERT_TRUE(notification);
EXPECT_EQ(
l10n_util::GetStringFUTF16(
@@ -558,7 +581,8 @@
const std::u16string app3 = u"app3";
LaunchAppAccessingCamera(app3);
- notification = FindNotificationById(kPrivacyHubCameraOffNotificationId);
+ notification = FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId);
ASSERT_TRUE(notification);
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE),
@@ -568,7 +592,8 @@
// contain the name of the two remaining applications.
CloseAppAccessingCamera(app2);
- notification = FindNotificationById(kPrivacyHubCameraOffNotificationId);
+ notification = FindNotificationById(
+ PrivacyHubNotificationController::kCombinedNotificationId);
ASSERT_TRUE(notification);
EXPECT_EQ(
l10n_util::GetStringFUTF16(
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
index 6867172..fb938a1 100644
--- a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
+++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
@@ -47,23 +47,7 @@
: input_stream_count_(CountActiveInputStreams()),
mic_mute_on_(CrasAudioHandler::Get()->IsInputMuted()),
mic_muted_by_mute_switch_(
- CrasAudioHandler::Get()->input_muted_by_microphone_mute_switch()),
- mute_switch_notification_(
- kNotificationId,
- NotificationCatalogName::kMicrophoneMute,
- PrivacyHubNotificationDescriptor{
- SensorDisabledNotificationDelegate::SensorSet{
- SensorDisabledNotificationDelegate::Sensor::kMicrophone},
- IDS_MICROPHONE_MUTED_BY_HW_SWITCH_NOTIFICATION_TITLE,
- IDS_ASH_LEARN_MORE,
- std::vector<int>{
- IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE,
- IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
- IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
- base::MakeRefCounted<
- PrivacyHubNotificationClickDelegate>(base::BindRepeating(
- PrivacyHubNotificationController::OpenSupportUrl,
- SensorDisabledNotificationDelegate::Sensor::kMicrophone))}) {
+ CrasAudioHandler::Get()->input_muted_by_microphone_mute_switch()) {
Shell::Get()->session_controller()->AddObserver(this);
CrasAudioHandler::Get()->AddAudioObserver(this);
}
@@ -168,35 +152,37 @@
void MicrophonePrivacySwitchController::SetMicrophoneNotificationVisible(
const bool visible) {
- mute_switch_notification_.Hide();
-
- if (mic_muted_by_mute_switch_ && visible) {
- mute_switch_notification_.Show();
- return;
- }
-
PrivacyHubNotificationController* const privacy_hub_notification_controller =
Shell::Get()->system_notification_controller()->privacy_hub();
+
if (visible) {
- privacy_hub_notification_controller->ShowSensorDisabledNotification(
- SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ if (mic_muted_by_mute_switch_) {
+ privacy_hub_notification_controller->ShowHardwareSwitchNotification(
+ SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ } else {
+ privacy_hub_notification_controller->ShowSoftwareSwitchNotification(
+ SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ }
+
} else {
- privacy_hub_notification_controller->RemoveSensorDisabledNotification(
+ privacy_hub_notification_controller->RemoveSoftwareSwitchNotification(
+ SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ privacy_hub_notification_controller->RemoveHardwareSwitchNotification(
SensorDisabledNotificationDelegate::Sensor::kMicrophone);
}
}
void MicrophonePrivacySwitchController::UpdateMicrophoneNotification() {
- if (mic_muted_by_mute_switch_) {
- mute_switch_notification_.Update();
- return;
- }
+ PrivacyHubNotificationController* const privacy_hub_notification_controller =
+ Shell::Get()->system_notification_controller()->privacy_hub();
- Shell::Get()
- ->system_notification_controller()
- ->privacy_hub()
- ->UpdateSensorDisabledNotification(
- SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ if (mic_muted_by_mute_switch_) {
+ privacy_hub_notification_controller->UpdateHardwareSwitchNotification(
+ SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ } else {
+ privacy_hub_notification_controller->UpdateSoftwareSwitchNotification(
+ SensorDisabledNotificationDelegate::Sensor::kMicrophone);
+ }
}
} // namespace ash
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.h b/ash/system/privacy_hub/microphone_privacy_switch_controller.h
index 863b581..2956063 100644
--- a/ash/system/privacy_hub/microphone_privacy_switch_controller.h
+++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.h
@@ -9,7 +9,6 @@
#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
-#include "ash/system/privacy_hub/privacy_hub_notification.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "components/prefs/pref_change_registrar.h"
@@ -21,8 +20,6 @@
: public CrasAudioHandler::AudioObserver,
public SessionObserver {
public:
- static constexpr char kNotificationId[] = "ash://microphone_mute";
-
MicrophonePrivacySwitchController();
MicrophonePrivacySwitchController(const MicrophonePrivacySwitchController&) =
delete;
@@ -60,7 +57,6 @@
size_t input_stream_count_ = 0;
bool mic_mute_on_ = false;
bool mic_muted_by_mute_switch_ = false;
- PrivacyHubNotification mute_switch_notification_;
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
};
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc
index fc1e556..80fea77 100644
--- a/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc
+++ b/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc
@@ -19,6 +19,7 @@
#include "ash/system/privacy_hub/microphone_privacy_switch_controller.h"
#include "ash/system/privacy_hub/privacy_hub_controller.h"
#include "ash/system/privacy_hub/privacy_hub_metrics.h"
+#include "ash/system/privacy_hub/privacy_hub_notification_controller.h"
#include "ash/test/ash_test_base.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
@@ -30,6 +31,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/public/cpp/notification.h"
namespace ash {
@@ -93,6 +95,31 @@
MOCK_METHOD(void, MicrophoneHardwareToggleChanged, (bool), (override));
};
+class RemoveNotificationWaiter : public message_center::MessageCenterObserver {
+ public:
+ explicit RemoveNotificationWaiter(const std::string& notification_id)
+ : notification_id_(notification_id) {
+ message_center::MessageCenter::Get()->AddObserver(this);
+ }
+ ~RemoveNotificationWaiter() override {
+ message_center::MessageCenter::Get()->RemoveObserver(this);
+ }
+
+ void Wait() { run_loop_.Run(); }
+
+ // message_center::MessageCenterObserver:
+ void OnNotificationRemoved(const std::string& notification_id,
+ const bool by_user) override {
+ if (notification_id == notification_id_) {
+ run_loop_.Quit();
+ }
+ }
+
+ private:
+ const std::string notification_id_;
+ base::RunLoop run_loop_;
+};
+
} // namespace
class PrivacyHubMicrophoneControllerTest : public AshTestBase {
@@ -135,30 +162,44 @@
->GetBoolean(prefs::kUserMicrophoneAllowed);
}
- message_center::Notification* GetNotification() {
+ bool IsAnyMicNotificationVisible() {
+ return GetSWSwitchNotification() != nullptr ||
+ GetHWSwitchNotification() != nullptr;
+ }
+
+ message_center::Notification* GetSWSwitchNotification() {
return message_center::MessageCenter::Get()->FindNotificationById(
- MicrophonePrivacySwitchController::kNotificationId);
+ PrivacyHubNotificationController::kCombinedNotificationId);
}
- message_center::Notification* GetPopupNotification() {
+ message_center::Notification* GetHWSwitchNotification() {
+ return message_center::MessageCenter::Get()->FindNotificationById(
+ PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
+ }
+
+ message_center::Notification* GetSWSwitchPopupNotification() {
return message_center::MessageCenter::Get()->FindPopupNotificationById(
- MicrophonePrivacySwitchController::kNotificationId);
+ PrivacyHubNotificationController::kCombinedNotificationId);
}
- void MarkPopupAsShown() {
- message_center::MessageCenter::Get()->MarkSinglePopupAsShown(
- MicrophonePrivacySwitchController::kNotificationId, true);
+ message_center::Notification* GetHWSwitchPopupNotification() {
+ return message_center::MessageCenter::Get()->FindPopupNotificationById(
+ PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
}
- void ClickOnNotificationButton() {
+ void MarkPopupAsShown(const std::string& id) {
+ message_center::MessageCenter::Get()->MarkSinglePopupAsShown(id, true);
+ }
+
+ void ClickOnNotificationButton(const std::string& id) {
message_center::MessageCenter::Get()->ClickOnNotificationButton(
- MicrophonePrivacySwitchController::kNotificationId,
- /*button_index=*/0);
+ id, /*button_index=*/0);
}
- void ClickOnNotificationBody() {
- message_center::MessageCenter::Get()->ClickOnNotification(
- MicrophonePrivacySwitchController::kNotificationId);
+ void ClickOnNotificationBody(const std::string& id) {
+ message_center::MessageCenter::Get()->ClickOnNotification(id);
}
void SetMicrophoneMuteSwitchState(bool muted) {
@@ -175,8 +216,9 @@
false, CrasAudioHandler::InputMuteChangeMethod::kOther);
}
- void WaitUntilNotificationRemoved() {
- task_environment()->FastForwardBy(PrivacyHubNotification::kMinShowTime);
+ void WaitUntilNotificationRemoved(const std::string& notification_id) {
+ RemoveNotificationWaiter notification_waiter(notification_id);
+ notification_waiter.Wait();
}
void LaunchApp(absl::optional<std::u16string> app_name) {
@@ -247,57 +289,66 @@
TEST_F(PrivacyHubMicrophoneControllerTest, SimpleMuteUnMute) {
// No notification initially.
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Or when we mute.
MuteMicrophone();
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Or when we unmute.
UnMuteMicrophone();
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
}
TEST_F(PrivacyHubMicrophoneControllerTest, LaunchAppUsingMicrophone) {
// No notification initially.
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// No notification when we unmute.
UnMuteMicrophone();
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Mute the mic, still no notification.
MuteMicrophone();
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Launch an app that's using the mic. The microphone mute notification should
// show as a popup.
LaunchApp(u"junior");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
// Notification should not be pinned.
- EXPECT_FALSE(GetNotification()->rich_notification_data().pinned);
+ EXPECT_FALSE(GetSWSwitchNotification()->rich_notification_data().pinned);
// Unmute again, notification goes down.
UnMuteMicrophone();
- WaitUntilNotificationRemoved();
- EXPECT_FALSE(GetNotification());
+
+ WaitUntilNotificationRemoved(
+ PrivacyHubNotificationController::kCombinedNotificationId);
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
}
TEST_F(PrivacyHubMicrophoneControllerTest,
SilentNotificationOnMuteWhileMicInUse) {
// No notification initially.
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Launch an app that's using the mic, no notification because the microphone
// is not muted.
LaunchApp(u"junior");
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Mute the mic, a notification should be shown and also popup.
MuteMicrophone();
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest,
@@ -306,18 +357,19 @@
MuteMicrophone();
LaunchApp(u"junior");
- ASSERT_TRUE(GetNotification());
- ASSERT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
// Mark the notification as read.
- MarkPopupAsShown();
- ASSERT_FALSE(GetPopupNotification());
+ MarkPopupAsShown(PrivacyHubNotificationController::kCombinedNotificationId);
+
+ EXPECT_FALSE(GetSWSwitchPopupNotification());
// Add an app, and verify the notification popup gets shown.
LaunchApp(u"rose");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest, RemovingStreamDoesNotShowPopup) {
@@ -326,25 +378,27 @@
LaunchApp(u"junior");
LaunchApp(u"rose");
- ASSERT_TRUE(GetNotification());
- ASSERT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
// Mark the notification as read.
- MarkPopupAsShown();
- ASSERT_FALSE(GetPopupNotification());
+ MarkPopupAsShown(PrivacyHubNotificationController::kCombinedNotificationId);
+
+ ASSERT_FALSE(GetSWSwitchPopupNotification());
// Close an active app, and verify that the notification popup is not
// reshown.
CloseApp(u"rose");
- EXPECT_TRUE(GetNotification());
- EXPECT_FALSE(GetPopupNotification());
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_FALSE(GetSWSwitchPopupNotification());
// The notification should be removed if all apps are closed.
CloseApp(u"junior");
- WaitUntilNotificationRemoved();
- EXPECT_FALSE(GetNotification());
+ WaitUntilNotificationRemoved(
+ PrivacyHubNotificationController::kCombinedNotificationId);
+ EXPECT_FALSE(GetSWSwitchNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest, SwMuteNotificationActionButton) {
@@ -352,15 +406,16 @@
LaunchApp(u"junior");
// The mute notification should have an action button.
- message_center::Notification* notification = GetNotification();
+ message_center::Notification* notification = GetSWSwitchNotification();
ASSERT_TRUE(notification);
EXPECT_EQ(1u, notification->buttons().size());
// Clicking the action button should unmute device.
- ClickOnNotificationButton();
- EXPECT_FALSE(CrasAudioHandler::Get()->IsInputMuted());
+ ClickOnNotificationButton(
+ PrivacyHubNotificationController::kCombinedNotificationId);
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(CrasAudioHandler::Get()->IsInputMuted());
+ EXPECT_FALSE(GetSWSwitchNotification());
EXPECT_EQ(histogram_tester().GetBucketCount(
privacy_hub_metrics::
kPrivacyHubMicrophoneEnabledFromNotificationHistogram,
@@ -373,15 +428,16 @@
LaunchApp(u"junior");
// The mute notification should have an action button.
- message_center::Notification* notification = GetNotification();
+ message_center::Notification* notification = GetSWSwitchNotification();
ASSERT_TRUE(notification);
EXPECT_EQ(1u, notification->buttons().size());
// Clicking the action button should unmute device.
- ClickOnNotificationBody();
- EXPECT_TRUE(CrasAudioHandler::Get()->IsInputMuted());
+ ClickOnNotificationBody(
+ PrivacyHubNotificationController::kCombinedNotificationId);
- EXPECT_FALSE(GetNotification());
+ EXPECT_TRUE(CrasAudioHandler::Get()->IsInputMuted());
+ EXPECT_FALSE(GetSWSwitchNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest, HwMuteNotificationActionButton) {
@@ -389,36 +445,41 @@
LaunchApp(u"junior");
- // The mute notification should have a "Learn more" button.
- message_center::Notification* notification = GetNotification();
+ // The hardware switch notification should be displayed. The notification
+ // should have a "Learn more" button.
+ EXPECT_FALSE(GetSWSwitchNotification());
+ message_center::Notification* notification = GetHWSwitchNotification();
ASSERT_TRUE(notification);
EXPECT_EQ(1u, notification->buttons().size());
// Clicking the "Learn more" button should open a new Chrome tab with the
// support link.
EXPECT_CALL(new_window_delegate(), OpenUrl).Times(1);
- ClickOnNotificationButton();
+ ClickOnNotificationButton(PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
EXPECT_TRUE(CrasAudioHandler::Get()->IsInputMuted());
SetMicrophoneMuteSwitchState(/*muted=*/false);
+
ASSERT_FALSE(CrasAudioHandler::Get()->IsInputMuted());
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
}
TEST_F(PrivacyHubMicrophoneControllerTest, HwMuteNotificationActionBody) {
SetMicrophoneMuteSwitchState(/*muted=*/true);
LaunchApp(u"junior");
- message_center::Notification* notification = GetNotification();
+ message_center::Notification* notification = GetHWSwitchNotification();
ASSERT_TRUE(notification);
- EXPECT_EQ(1u, notification->buttons().size());
- ClickOnNotificationBody();
-
- // Check that clicking the body has no effect and notification disappears.
+ // Check that clicking the body has no effect but notification disappears.
EXPECT_TRUE(CrasAudioHandler::Get()->IsInputMuted());
- EXPECT_FALSE(GetNotification());
+ ClickOnNotificationBody(PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
+
+ EXPECT_TRUE(CrasAudioHandler::Get()->IsInputMuted());
+ EXPECT_FALSE(GetHWSwitchNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest,
@@ -428,7 +489,7 @@
LaunchApp(u"junior");
// The mute notification should have an action button.
- message_center::Notification* notification = GetNotification();
+ message_center::Notification* notification = GetSWSwitchNotification();
ASSERT_TRUE(notification);
EXPECT_EQ(1u, notification->buttons().size());
EXPECT_EQ(l10n_util::GetStringUTF16(
@@ -438,7 +499,9 @@
// Toggle microphone mute switch and verify that new notification appears with
// a "Learn more" button.
SetMicrophoneMuteSwitchState(/*muted=*/true);
- notification = GetNotification();
+
+ EXPECT_FALSE(GetSWSwitchNotification());
+ notification = GetHWSwitchNotification();
ASSERT_TRUE(notification);
EXPECT_EQ(1u, notification->buttons().size());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE),
@@ -446,31 +509,42 @@
SetMicrophoneMuteSwitchState(/*muted=*/false);
ASSERT_FALSE(CrasAudioHandler::Get()->IsInputMuted());
- WaitUntilNotificationRemoved();
- EXPECT_FALSE(GetNotification());
+
+ WaitUntilNotificationRemoved(PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
}
TEST_F(PrivacyHubMicrophoneControllerTest,
- TogglingMuteSwitchDoesNotHideNotificationPopup) {
+ TogglingMuteSwitchCreatesHWPopupAndRemovesSWPopup) {
// Mute microphone, and activate an audio input stream.
MuteMicrophone();
-
LaunchApp(u"junior");
// Verify the notification popup is shown.
- ASSERT_TRUE(GetNotification());
- ASSERT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
- // Toggle microphone mute switch and verify that toggling mute switch alone
- // does not hide the notification popup.
+ // Toggle microphone mute switch and verify that toggling mute switch creates
+ // new hardware switch pop up notification and the software switch
+ // notification is removed.
SetMicrophoneMuteSwitchState(/*muted=*/true);
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ // The software switch notification is instantly hidden.
+ EXPECT_FALSE(GetSWSwitchNotification());
+
+ // Toggling the mute switch again should remove all microphone mute
+ // notifications.
SetMicrophoneMuteSwitchState(/*muted=*/false);
+
ASSERT_FALSE(CrasAudioHandler::Get()->IsInputMuted());
- WaitUntilNotificationRemoved();
- EXPECT_FALSE(GetNotification());
+ WaitUntilNotificationRemoved(PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
+ EXPECT_FALSE(GetSWSwitchNotification());
+ EXPECT_FALSE(GetHWSwitchNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest,
@@ -478,13 +552,14 @@
SetMicrophoneMuteSwitchState(/*muted=*/true);
LaunchApp(u"junior");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_TRUE(GetHWSwitchPopupNotification());
CloseApp(u"junior");
- WaitUntilNotificationRemoved();
- EXPECT_FALSE(GetNotification());
+ WaitUntilNotificationRemoved(PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
+ EXPECT_FALSE(GetHWSwitchNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest,
@@ -494,111 +569,125 @@
SetMicrophoneMuteSwitchState(/*muted=*/true);
// Notification should be shown and also popup.
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_TRUE(GetHWSwitchPopupNotification());
// Add another audio input stream, and verify the notification popup shows.
LaunchApp(u"junior1");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_TRUE(GetHWSwitchPopupNotification());
// Mark notification as read, and then remove an audio input stream.
- MarkPopupAsShown();
- ASSERT_FALSE(GetPopupNotification());
+ MarkPopupAsShown(PrivacyHubNotificationController::
+ kMicrophoneHardwareSwitchNotificationId);
+
+ ASSERT_FALSE(GetHWSwitchPopupNotification());
+
CloseApp(u"junior1");
// Verify that notification popup is not reshown.
- EXPECT_TRUE(GetNotification());
- EXPECT_FALSE(GetPopupNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_FALSE(GetHWSwitchPopupNotification());
// Adding another stream shows a popup again.
LaunchApp(u"rose");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_TRUE(GetHWSwitchPopupNotification());
}
TEST_F(PrivacyHubMicrophoneControllerTest, NotificationText) {
// No notification initially.
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Mute the mic using sw switch, still no notification.
MuteMicrophone();
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Launch an app that's using the mic, but the name of the app can not be
// determined.
LaunchApp(absl::nullopt);
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_MICROPHONE_MUTED_BY_SW_SWITCH_NOTIFICATION_TITLE),
- GetNotification()->title());
+ GetSWSwitchNotification()->title());
// The notification body should not contain any app name.
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE),
- GetNotification()->message());
+ GetSWSwitchNotification()->message());
// Launch an app that's using the mic, the name of the app can be determined.
LaunchApp(u"app1");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
// The notification body should contain name of the app.
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME, u"app1"),
- GetNotification()->message());
+ GetSWSwitchNotification()->message());
// Launch another app that's using the mic, the name of the app can be
// determined.
LaunchApp(u"app2");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
// The notification body should contain the two available app names in the
// order of most recently launched.
EXPECT_EQ(l10n_util::GetStringFUTF16(
IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES,
u"app2", u"app1"),
- GetNotification()->message());
+ GetSWSwitchNotification()->message());
// Launch yet another app that's using the mic, the name of the app can be
// determined.
LaunchApp(u"app3");
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
+
+ EXPECT_TRUE(GetSWSwitchNotification());
+ EXPECT_TRUE(GetSWSwitchPopupNotification());
// As more that two apps are attempting to use the microphone, we fall back to
// displaying the generic message in the notification.
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE),
- GetNotification()->message());
+ GetSWSwitchNotification()->message());
EXPECT_FALSE(
ui::MicrophoneMuteSwitchMonitor::Get()->microphone_mute_switch_on());
+ EXPECT_FALSE(GetHWSwitchNotification());
+
// Toggle the hw switch.
SetMicrophoneMuteSwitchState(/*muted=*/true);
- EXPECT_TRUE(GetNotification());
- EXPECT_TRUE(GetPopupNotification());
- // The title of the notification should be different when microphone is muted
- // by the hw switch.
+
+ EXPECT_TRUE(GetHWSwitchNotification());
+ EXPECT_TRUE(GetHWSwitchPopupNotification());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_MICROPHONE_MUTED_BY_HW_SWITCH_NOTIFICATION_TITLE),
- GetNotification()->title());
+ GetHWSwitchNotification()->title());
+ EXPECT_EQ(
+ l10n_util::GetStringUTF16(IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE),
+ GetHWSwitchNotification()->message());
}
TEST_F(PrivacyHubMicrophoneControllerTest, NotificationUpdatedWhenAppClosed) {
// No notification initially.
- EXPECT_FALSE(GetNotification());
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Mute the mic using sw switch, still no notification.
MuteMicrophone();
- EXPECT_FALSE(GetNotification());
+
+ EXPECT_FALSE(IsAnyMicNotificationVisible());
// Launch app1 that's accessing the mic, a notification should be displayed
// with the application name in the notification body.
const std::u16string app1 = u"app1";
LaunchApp(app1);
- message_center::Notification* notification_ptr = GetNotification();
+
+ message_center::Notification* notification_ptr = GetSWSwitchNotification();
ASSERT_TRUE(notification_ptr);
EXPECT_EQ(
l10n_util::GetStringFUTF16(
@@ -610,7 +699,8 @@
// notification body.
const std::u16string app2 = u"app2";
LaunchApp(app2);
- notification_ptr = GetNotification();
+
+ notification_ptr = GetSWSwitchNotification();
ASSERT_TRUE(notification_ptr);
EXPECT_EQ(l10n_util::GetStringFUTF16(
IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES,
@@ -620,7 +710,8 @@
// Close one of the applications. The notification message should be updated
// to only contain the name of the other application.
CloseApp(app1);
- notification_ptr = GetNotification();
+
+ notification_ptr = GetSWSwitchNotification();
ASSERT_TRUE(notification_ptr);
EXPECT_EQ(
l10n_util::GetStringFUTF16(
@@ -630,10 +721,10 @@
// Test the HW switch notification case.
// HW switch is turned ON.
SetMicrophoneMuteSwitchState(/*muted=*/true);
-
// Launch the closed app (app1) again.
LaunchApp(app1);
- notification_ptr = GetNotification();
+
+ notification_ptr = GetHWSwitchNotification();
ASSERT_TRUE(notification_ptr);
EXPECT_EQ(l10n_util::GetStringFUTF16(
IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES,
@@ -643,7 +734,8 @@
// Closing one of the applications should remove the name of that application
// from the hw switch notification message.
CloseApp(app2);
- notification_ptr = GetNotification();
+
+ notification_ptr = GetHWSwitchNotification();
ASSERT_TRUE(notification_ptr);
EXPECT_EQ(
l10n_util::GetStringFUTF16(
diff --git a/ash/system/privacy_hub/privacy_hub_notification.cc b/ash/system/privacy_hub/privacy_hub_notification.cc
index aedc762..e5d821f 100644
--- a/ash/system/privacy_hub/privacy_hub_notification.cc
+++ b/ash/system/privacy_hub/privacy_hub_notification.cc
@@ -29,6 +29,22 @@
namespace ash {
+bool operator<(const PrivacyHubNotificationDescriptor& descriptor1,
+ const PrivacyHubNotificationDescriptor& descriptor2) {
+ return descriptor1.sensors().ToEnumBitmask() <
+ descriptor2.sensors().ToEnumBitmask();
+}
+
+bool operator<(const PrivacyHubNotificationDescriptor& descriptor,
+ const uint64_t& sensors_bitmask) {
+ return descriptor.sensors().ToEnumBitmask() < sensors_bitmask;
+}
+
+bool operator<(const uint64_t& sensors_bitmask,
+ const PrivacyHubNotificationDescriptor& descriptor) {
+ return sensors_bitmask < descriptor.sensors().ToEnumBitmask();
+}
+
PrivacyHubNotificationClickDelegate::PrivacyHubNotificationClickDelegate(
base::RepeatingClosure button_click) {
button_callbacks_[0] = std::move(button_click);
@@ -71,11 +87,11 @@
PrivacyHubNotificationDescriptor::PrivacyHubNotificationDescriptor(
const SensorDisabledNotificationDelegate::SensorSet& sensors,
const int title_id,
- const int button_id,
+ const std::vector<int>& button_ids,
const std::vector<int>& message_ids,
const scoped_refptr<PrivacyHubNotificationClickDelegate> delegate)
: title_id_(title_id),
- button_id_(button_id),
+ button_ids_(button_ids),
sensors_(sensors),
message_ids_(message_ids),
delegate_(delegate) {
@@ -83,6 +99,8 @@
DCHECK(delegate);
DCHECK(message_ids.size() < 2u || !sensors.Empty())
<< "Specify at least one sensor when providing more than one message ID";
+ DCHECK_LE(button_ids.size(), 2u) << "Privacy hub notifications are not "
+ "supposed to have more than two buttons.";
}
PrivacyHubNotificationDescriptor::PrivacyHubNotificationDescriptor(
@@ -97,20 +115,28 @@
const std::string& id,
const ash::NotificationCatalogName catalog_name,
const PrivacyHubNotificationDescriptor& descriptor)
- : id_(id),
- message_ids_(descriptor.message_ids()),
- sensors_(descriptor.sensors()),
- delegate_(descriptor.delegate()),
- button_text_(l10n_util::GetStringUTF16(descriptor.button_id_)) {
+ : id_(id), sensors_(descriptor.sensors()), catalog_name_(catalog_name) {
+ notification_descriptors_.emplace(descriptor);
+ SetNotificationContent();
+
builder_.SetId(id)
.SetCatalogName(catalog_name)
- .SetDelegate(descriptor.delegate())
- .SetTitleId(descriptor.title_id_)
- .SetOptionalFields(MakeOptionalFields())
.SetSmallImage(vector_icons::kSettingsIcon)
.SetWarningLevel(message_center::SystemNotificationWarningLevel::NORMAL);
}
+PrivacyHubNotification::PrivacyHubNotification(
+ const std::string& id,
+ const ash::NotificationCatalogName catalog_name,
+ const std::vector<PrivacyHubNotificationDescriptor>& descriptors)
+ : PrivacyHubNotification(id, catalog_name, descriptors.at(0)) {
+ DCHECK_GT(descriptors.size(), 1u);
+
+ for (unsigned int i = 1; i < descriptors.size(); ++i) {
+ notification_descriptors_.emplace(descriptors.at(i));
+ }
+}
+
PrivacyHubNotification::~PrivacyHubNotification() = default;
void PrivacyHubNotification::Show() {
@@ -132,7 +158,16 @@
last_time_shown_ = base::Time::Now();
}
-void PrivacyHubNotification::Hide() {
+void PrivacyHubNotification::Hide(const bool ignore_delay) {
+ if (ignore_delay) {
+ if (remove_timer_.IsRunning()) {
+ remove_timer_.Stop();
+ }
+ RemoveNotification(id_);
+ last_time_shown_.reset();
+ return;
+ }
+
if (!last_time_shown_) {
return;
}
@@ -157,16 +192,20 @@
}
}
-void PrivacyHubNotification::SetSecondButton(base::RepeatingClosure callback,
- int title_id) {
- message_center::RichNotificationData optional_fields = MakeOptionalFields();
- optional_fields.buttons.emplace_back(l10n_util::GetStringUTF16(title_id));
- builder_.SetOptionalFields(optional_fields);
- delegate_->SetSecondButtonCallback(std::move(callback));
+void PrivacyHubNotification::SetSensors(
+ const SensorDisabledNotificationDelegate::SensorSet sensors) {
+ DCHECK_GT(notification_descriptors_.size(), 1u)
+ << "`sensors_` should only be updated when multiple notification "
+ "descriptors are provided.";
+
+ if (sensors_ != sensors) {
+ sensors_ = sensors;
+ has_sensors_changed_ = true;
+ }
}
-std::vector<std::u16string> PrivacyHubNotification::GetAppsAccessingSensors()
- const {
+std::vector<std::u16string> PrivacyHubNotification::GetAppsAccessingSensors(
+ const size_t number_of_apps) const {
std::vector<std::u16string> app_names;
if (SensorDisabledNotificationDelegate* delegate =
@@ -177,7 +216,7 @@
if (!base::Contains(app_names, app)) {
app_names.push_back(app);
}
- if (app_names.size() == message_ids_.size()) {
+ if (app_names.size() == number_of_apps) {
return app_names;
}
}
@@ -188,22 +227,41 @@
}
void PrivacyHubNotification::SetNotificationContent() {
- const std::vector<std::u16string> apps = GetAppsAccessingSensors();
+ auto descriptor = notification_descriptors_.find(sensors_.ToEnumBitmask());
+ DCHECK(descriptor != notification_descriptors_.end());
- if (const size_t num_apps = apps.size(); num_apps < message_ids_.size()) {
- builder_.SetMessageWithArgs(message_ids_.at(num_apps), apps);
- } else {
- builder_.SetMessageId(message_ids_.at(0));
+ if (has_sensors_changed_) {
+ message_center::RichNotificationData optional_fields;
+ optional_fields.remove_on_click = true;
+
+ for (int button_id : descriptor->button_ids()) {
+ optional_fields.buttons.emplace_back(
+ l10n_util::GetStringUTF16(button_id));
+ }
+
+ builder_.SetDelegate(descriptor->delegate())
+ .SetOptionalFields(optional_fields);
+
+ if (catalog_name_ != NotificationCatalogName::kCameraPrivacySwitch) {
+ builder_.SetTitleId(descriptor->title_id_);
+ }
+
+ has_sensors_changed_ = false;
}
-}
-message_center::RichNotificationData
-PrivacyHubNotification::MakeOptionalFields() const {
- message_center::RichNotificationData optional_fields;
- optional_fields.remove_on_click = true;
- optional_fields.buttons.emplace_back(button_text_);
+ if (catalog_name_ == NotificationCatalogName::kCameraPrivacySwitch) {
+ return;
+ }
- return optional_fields;
+ const std::vector<std::u16string> apps =
+ GetAppsAccessingSensors(descriptor->message_ids().size());
+
+ if (const size_t num_apps = apps.size();
+ num_apps < descriptor->message_ids().size()) {
+ builder_.SetMessageWithArgs(descriptor->message_ids().at(num_apps), apps);
+ } else {
+ builder_.SetMessageId(descriptor->message_ids().at(0));
+ }
}
} // namespace ash
diff --git a/ash/system/privacy_hub/privacy_hub_notification.h b/ash/system/privacy_hub/privacy_hub_notification.h
index 6612971..d0e904a 100644
--- a/ash/system/privacy_hub/privacy_hub_notification.h
+++ b/ash/system/privacy_hub/privacy_hub_notification.h
@@ -5,6 +5,7 @@
#ifndef ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_NOTIFICATION_H_
#define ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_NOTIFICATION_H_
+#include <set>
#include <string>
#include <vector>
@@ -61,7 +62,7 @@
PrivacyHubNotificationDescriptor(
const SensorDisabledNotificationDelegate::SensorSet& sensors,
int title_id,
- int button_id,
+ const std::vector<int>& button_ids,
const std::vector<int>& message_ids,
scoped_refptr<PrivacyHubNotificationClickDelegate> delegate);
PrivacyHubNotificationDescriptor(
@@ -70,6 +71,8 @@
const PrivacyHubNotificationDescriptor& other);
~PrivacyHubNotificationDescriptor();
+ const std::vector<int>& button_ids() const { return button_ids_; }
+
const SensorDisabledNotificationDelegate::SensorSet& sensors() const {
return sensors_;
}
@@ -81,9 +84,9 @@
}
int title_id_;
- int button_id_;
private:
+ std::vector<int> button_ids_;
SensorDisabledNotificationDelegate::SensorSet sensors_;
std::vector<int> message_ids_;
scoped_refptr<PrivacyHubNotificationClickDelegate> delegate_;
@@ -98,28 +101,50 @@
// Create a new notification.
// When calling `Show() or `Update()`:
- // If `sensors_` is empty, the generic notification message will be displayed.
+ // If `sensors_` is empty, the generic notification message from `descriptor`
+ // will be displayed.
// If `sensors_` is non-empty and `n` applications are using the sensors in
// `sensors_`, the displayed notification message will contain `n` application
- // names. If a notification message with `n` application names is not
- // provided, the generic notification message will be displayed.
+ // names. If `descriptor` does not contain a notification message with `n`
+ // application names, the generic notification message from `descriptor` will
+ // be displayed.
PrivacyHubNotification(const std::string& id,
NotificationCatalogName catalog_name,
const PrivacyHubNotificationDescriptor& descriptor);
+
+ // When PrivacyHubNotification is constructed with multiple
+ // `PrivacyHubNotificationDescriptor`s, which descriptor to use will be
+ // decided depending on the value of `sensors_`. When `sensors_` changes, the
+ // descriptor to use will also change.
+ //`descriptors` must have multiple `PrivacyHubNotificationDescriptor` objects,
+ // use the previous constructor otherwise please.
+ PrivacyHubNotification(
+ const std::string& id,
+ NotificationCatalogName catalog_name,
+ const std::vector<PrivacyHubNotificationDescriptor>& descriptors);
+
PrivacyHubNotification(PrivacyHubNotification&&) = delete;
PrivacyHubNotification& operator=(PrivacyHubNotification&&) = delete;
+
~PrivacyHubNotification();
// Show the notification to the user for at least `kMinShowTime`. Every time
// `Show()` is called, the notification will pop up. For silent updates, use
- // the `Update()` function. Calls to `Hide()` are delayed until `kMinShowTime`
- // time has passed and the notification is hidden then.
+ // the `Update()` function.
void Show();
- // Hide the notification from the user if it has already been shown for at
- // least `kMinShowTime`. If not the notification will be shown for the
- // remaining time and then hidden.
- void Hide();
+ // Hide the notification from the user. Calls to `Hide()` are delayed until
+ // `kMinShowTime` time has passed since the time notification was last
+ // displayed.
+ // When `ignore_delay` is true, the notification is instantly hidden from the
+ // message center. `ignore_delay` should always be false except for some
+ // special cases.
+ // For example, microphone software switch notification and hardware switch
+ // notification are represented by different notification objects and the
+ // notifications represent the same information except the action buttons. In
+ // such cases, displaying both of the simultaneously may seem redundant. This
+ // is a perfect example to use `Hide()` with `ignore_delay = true`.
+ void Hide(bool ignore_delay = false);
// Silently updates the notification when needed, for example, when an
// application stops accessing a sensor and the name of that application needs
@@ -127,10 +152,8 @@
// again.
void Update();
- // Add an additional button to the notification. The button title will be
- // generated from the `title_id`. Clicking the button will invoke the
- // `callback`. Only one additional button can be active at the same time.
- void SetSecondButton(base::RepeatingClosure callback, int title_id);
+ // Updates the value of `sensors_`.
+ void SetSensors(SensorDisabledNotificationDelegate::SensorSet sensors);
// Get the underlying `SystemNotificationBuilder` to do modifications beyond
// what this wrapper allows you to do. If you change the ID of the message
@@ -138,26 +161,48 @@
SystemNotificationBuilder& builder() { return builder_; }
private:
- // Get names of apps accessing sensors in `sensors_`. At most
- // `message_ids_.size()` elements will be returned.
- std::vector<std::u16string> GetAppsAccessingSensors() const;
+ // Get names of apps accessing sensors in `sensors_`. At most `number_of_apps`
+ // elements will be returned.
+ std::vector<std::u16string> GetAppsAccessingSensors(
+ size_t number_of_apps) const;
- // Sets the content(message, title, buttons etc.) of the notification
- // depending on the values of `sensors_` and `message_ids_`.
+ // Propagates information about the update in notification content (message,
+ // title, buttons etc.) to the underlying `SystemNotificationBuilder`. This is
+ // always done before showing or updating a notification.
void SetNotificationContent();
- // Create an object of optional data fields with the defaults applying to
- // every Privacy Hub notification.
- message_center::RichNotificationData MakeOptionalFields() const;
-
std::string id_;
- SystemNotificationBuilder builder_;
- std::vector<int> message_ids_;
+
+ // A set of `PrivacyHubNotificationDescriptor`s. Appropriate
+ // `PrivacyHubNotificationDescriptor` for a specific `SensorSet` can be found
+ // using the standard `find` function. `sensors_.ToEnumBitmask()` can be used
+ // as the key for the `find` function.
+ std::set<PrivacyHubNotificationDescriptor, std::less<>>
+ notification_descriptors_;
+
SensorDisabledNotificationDelegate::SensorSet sensors_;
+
+ // `notification_descriptors_` is a set of
+ // `PrivacyHubNotificationDescriptor`s. The content in the descriptors are
+ // used to update the underlying `SystemNotificationBuilder`. Before a call to
+ // `Show()` or `Update()`, the underlying builder needs to be updated. Content
+ // of which descriptor to use to update the builder depends on the value
+ // current value of `sensors_` enumset.
+ // `has_sensors_changed_` being true means that `sensors_` was updated but the
+ // underlying builder was not updated after that.
+ bool has_sensors_changed_ = true;
+
+ SystemNotificationBuilder builder_;
+
absl::optional<base::Time> last_time_shown_;
base::OneShotTimer remove_timer_;
- scoped_refptr<PrivacyHubNotificationClickDelegate> delegate_;
- std::u16string button_text_;
+
+ // TODO(b/271809217): Refactor camera HW switch notification implementation
+ // Notification for the camera hardware switch is currently using only a
+ // subset of `PrivacyHubNotification` properties. `catalog_name_` is stored to
+ // determine if the notification is for the camera hardware switch to handle
+ // it specially.
+ NotificationCatalogName catalog_name_;
};
} // namespace ash
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller.cc b/ash/system/privacy_hub/privacy_hub_notification_controller.cc
index d36fa4c..6f33200 100644
--- a/ash/system/privacy_hub/privacy_hub_notification_controller.cc
+++ b/ash/system/privacy_hub/privacy_hub_notification_controller.cc
@@ -14,6 +14,7 @@
#include "ash/system/privacy_hub/microphone_privacy_switch_controller.h"
#include "ash/system/privacy_hub/privacy_hub_metrics.h"
#include "ash/system/privacy_hub/privacy_hub_notification.h"
+#include "base/notreached.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "ui/message_center/message_center.h"
@@ -29,45 +30,38 @@
constexpr char kLearnMoreUrl[] =
"https://support.google.com/chromebook/?p=privacy_hub";
+void LogInvalidSensor(const SensorDisabledNotificationDelegate::Sensor sensor) {
+ NOTREACHED() << "Invalid sensor: "
+ << static_cast<std::underlying_type_t<
+ SensorDisabledNotificationDelegate::Sensor>>(sensor);
+}
+
} // namespace
PrivacyHubNotificationController::PrivacyHubNotificationController() {
- sw_notifications_.emplace(
- Sensor::kCamera,
- std::make_unique<PrivacyHubNotification>(
- kPrivacyHubCameraOffNotificationId,
- NotificationCatalogName::kPrivacyHubCamera,
- PrivacyHubNotificationDescriptor{
- SensorDisabledNotificationDelegate::SensorSet{Sensor::kCamera},
- IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_TITLE,
- IDS_PRIVACY_HUB_TURN_ON_CAMERA_ACTION_BUTTON,
- std::vector<int>{
- IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE,
- IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
- IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
- base::MakeRefCounted<PrivacyHubNotificationClickDelegate>(
- base::BindRepeating([]() {
- CameraPrivacySwitchController::
- SetAndLogCameraPreferenceFromNotification(true);
- }))}));
+ auto camera_notification_descriptor = PrivacyHubNotificationDescriptor(
+ SensorSet{Sensor::kCamera}, IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_TITLE,
+ std::vector<int>{IDS_PRIVACY_HUB_TURN_ON_CAMERA_ACTION_BUTTON},
+ std::vector<int>{
+ IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE,
+ IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
+ IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
+ base::MakeRefCounted<PrivacyHubNotificationClickDelegate>(
+ base::BindRepeating([]() {
+ CameraPrivacySwitchController::
+ SetAndLogCameraPreferenceFromNotification(true);
+ })));
- sw_notifications_.emplace(
- Sensor::kMicrophone,
- std::make_unique<PrivacyHubNotification>(
- MicrophonePrivacySwitchController::kNotificationId,
- NotificationCatalogName::kMicrophoneMute,
- PrivacyHubNotificationDescriptor{
- SensorDisabledNotificationDelegate::SensorSet{
- Sensor::kMicrophone},
- IDS_MICROPHONE_MUTED_BY_SW_SWITCH_NOTIFICATION_TITLE,
- IDS_MICROPHONE_MUTED_NOTIFICATION_ACTION_BUTTON,
- std::vector<int>{
- IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE,
- IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
- IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
- base::MakeRefCounted<PrivacyHubNotificationClickDelegate>(
- base::BindRepeating(
- []() { SetAndLogMicrophoneMute(false); }))}));
+ auto microphone_notification_descriptor = PrivacyHubNotificationDescriptor(
+ SensorSet{Sensor::kMicrophone},
+ IDS_MICROPHONE_MUTED_BY_SW_SWITCH_NOTIFICATION_TITLE,
+ std::vector<int>{IDS_MICROPHONE_MUTED_NOTIFICATION_ACTION_BUTTON},
+ std::vector<int>{
+ IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE,
+ IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
+ IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
+ base::MakeRefCounted<PrivacyHubNotificationClickDelegate>(
+ base::BindRepeating([]() { SetAndLogMicrophoneMute(false); })));
auto combined_delegate = base::MakeRefCounted<
PrivacyHubNotificationClickDelegate>(base::BindRepeating([]() {
@@ -75,53 +69,155 @@
CameraPrivacySwitchController::SetAndLogCameraPreferenceFromNotification(
true);
}));
- combined_delegate->SetMessageClickCallback(base::BindRepeating(
- &PrivacyHubNotificationController::HandleNotificationMessageClicked,
- weak_ptr_factory_.GetWeakPtr()));
+
+ combined_delegate->SetSecondButtonCallback(base::BindRepeating(
+ &PrivacyHubNotificationController::OpenPrivacyHubSettingsPage));
+
+ auto combined_notification_descriptor = PrivacyHubNotificationDescriptor(
+ SensorSet{Sensor::kCamera, Sensor::kMicrophone},
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE,
+ std::vector<int>{
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_BUTTON},
+ std::vector<int>{
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE,
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
+ combined_delegate);
combined_notification_ = std::make_unique<PrivacyHubNotification>(
kCombinedNotificationId, NotificationCatalogName::kPrivacyHubMicAndCamera,
- PrivacyHubNotificationDescriptor{
- SensorDisabledNotificationDelegate::SensorSet{Sensor::kCamera,
- Sensor::kMicrophone},
- IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE,
- IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_BUTTON,
- std::vector<int>{
- IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE,
- IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
- IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
- combined_delegate});
+ std::vector<PrivacyHubNotificationDescriptor>{
+ camera_notification_descriptor, microphone_notification_descriptor,
+ combined_notification_descriptor});
- combined_notification_->SetSecondButton(
- base::BindRepeating(
- &PrivacyHubNotificationController::OpenPrivacyHubSettingsPage),
- IDS_PRIVACY_HUB_OPEN_SETTINGS_PAGE_BUTTON);
+ microphone_hw_switch_notification_ = std::make_unique<PrivacyHubNotification>(
+ kMicrophoneHardwareSwitchNotificationId,
+ NotificationCatalogName::kMicrophoneMute,
+ PrivacyHubNotificationDescriptor{
+ SensorDisabledNotificationDelegate::SensorSet{Sensor::kMicrophone},
+ IDS_MICROPHONE_MUTED_BY_HW_SWITCH_NOTIFICATION_TITLE,
+ std::vector<int>{IDS_ASH_LEARN_MORE},
+ std::vector<int>{
+ IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE,
+ IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
+ IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE_WITH_TWO_APP_NAMES},
+ base::MakeRefCounted<PrivacyHubNotificationClickDelegate>(
+ base::BindRepeating(
+ PrivacyHubNotificationController::OpenSupportUrl,
+ SensorDisabledNotificationDelegate::Sensor::kMicrophone))});
}
PrivacyHubNotificationController::~PrivacyHubNotificationController() = default;
-void PrivacyHubNotificationController::ShowSensorDisabledNotification(
+void PrivacyHubNotificationController::ShowSoftwareSwitchNotification(
const Sensor sensor) {
- sensors_.Put(sensor);
-
- ShowAllActiveNotifications(sensor);
-}
-
-void PrivacyHubNotificationController::RemoveSensorDisabledNotification(
- const Sensor sensor) {
- sensors_.Remove(sensor);
-
- if (!sensors_.HasAny(combinable_sensors_)) {
- ignore_new_combinable_notifications_ = false;
+ switch (sensor) {
+ case Sensor::kMicrophone: {
+ // Microphone software switch notification will be displayed now. If the
+ // hardware switch notification is still not cleared, let's force clear
+ // it.
+ microphone_hw_switch_notification_->Hide(/*ignore_delay=*/true);
+ [[fallthrough]];
+ }
+ case Sensor::kCamera: {
+ AddSensor(sensor);
+ combined_notification_->Show();
+ break;
+ }
+ default: {
+ LogInvalidSensor(sensor);
+ break;
+ }
}
-
- ShowAllActiveNotifications(sensor);
}
-void PrivacyHubNotificationController::UpdateSensorDisabledNotification(
+void PrivacyHubNotificationController::RemoveSoftwareSwitchNotification(
const Sensor sensor) {
- sw_notifications_.at(sensor)->Update();
- combined_notification_->Update();
+ switch (sensor) {
+ case Sensor::kCamera: {
+ [[fallthrough]];
+ }
+ case Sensor::kMicrophone: {
+ RemoveSensor(sensor);
+ if (!sensors_.Empty()) {
+ combined_notification_->Update();
+ } else {
+ combined_notification_->Hide();
+ }
+ break;
+ }
+ default: {
+ LogInvalidSensor(sensor);
+ break;
+ }
+ }
+}
+
+void PrivacyHubNotificationController::UpdateSoftwareSwitchNotification(
+ const Sensor sensor) {
+ switch (sensor) {
+ case Sensor::kCamera: {
+ [[fallthrough]];
+ }
+ case Sensor::kMicrophone: {
+ combined_notification_->Update();
+ break;
+ }
+ default: {
+ LogInvalidSensor(sensor);
+ break;
+ }
+ }
+}
+
+void PrivacyHubNotificationController::ShowHardwareSwitchNotification(
+ const Sensor sensor) {
+ switch (sensor) {
+ case Sensor::kMicrophone: {
+ RemoveSensor(sensor);
+ if (!sensors_.Empty()) {
+ combined_notification_->Update();
+ } else {
+ // As the hardware switch notification for microphone will be displayed
+ // now, let's force remove the sw switch notification.
+ combined_notification_->Hide(/*ignore_delay=*/true);
+ }
+ microphone_hw_switch_notification_->Show();
+ break;
+ }
+ default: {
+ LogInvalidSensor(sensor);
+ break;
+ }
+ }
+}
+
+void PrivacyHubNotificationController::RemoveHardwareSwitchNotification(
+ const Sensor sensor) {
+ switch (sensor) {
+ case Sensor::kMicrophone: {
+ microphone_hw_switch_notification_->Hide();
+ break;
+ }
+ default: {
+ LogInvalidSensor(sensor);
+ break;
+ }
+ }
+}
+
+void PrivacyHubNotificationController::UpdateHardwareSwitchNotification(
+ const Sensor sensor) {
+ switch (sensor) {
+ case Sensor::kMicrophone: {
+ microphone_hw_switch_notification_->Update();
+ break;
+ }
+ default: {
+ LogInvalidSensor(sensor);
+ break;
+ }
+ }
}
void PrivacyHubNotificationController::OpenPrivacyHubSettingsPage() {
@@ -148,43 +244,14 @@
NewWindowDelegate::Disposition::kNewForegroundTab);
}
-void PrivacyHubNotificationController::ShowAllActiveNotifications(
- const Sensor changed_sensor) {
- message_center::MessageCenter* message_center =
- message_center::MessageCenter::Get();
- DCHECK(message_center);
-
- if (combinable_sensors_.Has(changed_sensor)) {
- combined_notification_->Hide();
-
- if (ignore_new_combinable_notifications_)
- return;
-
- if (sensors_.HasAll(combinable_sensors_)) {
- for (Sensor sensor : combinable_sensors_) {
- sw_notifications_.at(sensor)->Hide();
- }
-
- combined_notification_->Show();
-
- return;
- }
- }
-
- // Remove the notification for the current sensor in case the sensor is
- // no longer active it won't be shown again in the for loop later.
- // The other case where the sensor is added (again) to the set this
- // (re)surfaces the notification, e.g. because a different app now wants to
- // access the sensor.
- sw_notifications_.at(changed_sensor)->Hide();
-
- for (const Sensor active_sensor : sensors_) {
- sw_notifications_.at(active_sensor)->Show();
- }
+void PrivacyHubNotificationController::AddSensor(Sensor sensor) {
+ sensors_.Put(sensor);
+ combined_notification_->SetSensors(sensors_);
}
-void PrivacyHubNotificationController::HandleNotificationMessageClicked() {
- ignore_new_combinable_notifications_ = true;
+void PrivacyHubNotificationController::RemoveSensor(Sensor sensor) {
+ sensors_.Remove(sensor);
+ combined_notification_->SetSensors(sensors_);
}
} // namespace ash
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller.h b/ash/system/privacy_hub/privacy_hub_notification_controller.h
index 09cfc8d..60adf94 100644
--- a/ash/system/privacy_hub/privacy_hub_notification_controller.h
+++ b/ash/system/privacy_hub/privacy_hub_notification_controller.h
@@ -10,8 +10,6 @@
#include "ash/ash_export.h"
#include "ash/public/cpp/sensor_disabled_notification_delegate.h"
#include "ash/system/privacy_hub/privacy_hub_notification.h"
-#include "base/containers/flat_map.h"
-#include "base/memory/weak_ptr.h"
namespace ash {
@@ -29,20 +27,41 @@
const PrivacyHubNotificationController&) = delete;
~PrivacyHubNotificationController();
- // Called by any sensor system when a notification for `sensor`
- // should be shown to the user.
- void ShowSensorDisabledNotification(Sensor sensor);
+ // Called by any sensor system when a software switch notification for
+ // `sensor` should be shown to the user.
+ void ShowSoftwareSwitchNotification(Sensor sensor);
- // Called by any sensor system when a notification for `sensor`
- // should be removed from the notification center and popups.
- void RemoveSensorDisabledNotification(Sensor sensor);
+ // Called by any sensor system when a software switch notification for
+ // `sensor` should be removed from the notification center and popups.
+ void RemoveSoftwareSwitchNotification(Sensor sensor);
- // Called by any sensor system when a notification for `sensor` should be
- // updated, for example, when an application stops accessing `sensor`.
- void UpdateSensorDisabledNotification(Sensor sensor);
+ // Called by any sensor system when a software switch notification for
+ // `sensor` should be updated, for example, when an application stops
+ // accessing `sensor`.
+ void UpdateSoftwareSwitchNotification(Sensor sensor);
+ // Called by any sensor system when a hardware switch notification for
+ // `sensor` should be shown to the user.
+ void ShowHardwareSwitchNotification(Sensor sensor);
+
+ // Called by any sensor system when a hardware switch notification for
+ // `sensor` should be removed from the notification center and popups.
+ void RemoveHardwareSwitchNotification(Sensor sensor);
+
+ // Called by any sensor system when a hardware switch notification for
+ // `sensor` should be updated, for example, when an application stops
+ // accessing `sensor`.
+ void UpdateHardwareSwitchNotification(Sensor sensor);
+
+ // This same id will be used for
+ // - microphone software switch notification
+ // - camera software switch notification
+ // - microphone and camera combined notification
static constexpr const char kCombinedNotificationId[] =
- "ash.system.privacy_hub.enable_microphone_and_camera";
+ "ash.system.privacy_hub.enable_microphone_and/or_camera";
+
+ static constexpr const char kMicrophoneHardwareSwitchNotificationId[] =
+ "ash://microphone_hardware_mute";
// Open the Privacy Hub settings page and log that this interaction came from
// a notification.
@@ -53,26 +72,22 @@
static void OpenSupportUrl(Sensor sensor);
private:
- // Show all notifications that are currently active and combine them if
- // necessary. From the `changed_sensor` in combination with `sensors_`,
- // `combinable_sensors_` and `ignore_new_combinable_notifications_` the
- // appropriate notification will be shown and unnecessary notifications
- // removed if necessary.
- void ShowAllActiveNotifications(Sensor changed_sensor);
-
- void HandleNotificationMessageClicked();
+ void AddSensor(SensorDisabledNotificationDelegate::Sensor sensor);
+ void RemoveSensor(SensorDisabledNotificationDelegate::Sensor sensor);
const SensorSet combinable_sensors_{Sensor::kMicrophone, Sensor::kCamera};
- // Flag to keep track if the user opened the settings page and don't show
- // them new notifications of sensors that can be combined or the combined
- // notification until the number of active uses falls to 0.
- bool ignore_new_combinable_notifications_{false};
+
+ // `combined_notification_` will be displayed for the sensors which are
+ // currently in `sensors_`. Only `combinable_sensors_` can be in `sensors_`.
SensorSet sensors_;
+
+ // This PrivacyHubNotification object will be used to display
+ // - microphone software switch notification
+ // - camera software switch notification
+ // - microphone and camera combined notification
std::unique_ptr<PrivacyHubNotification> combined_notification_;
- base::flat_map<Sensor, std::unique_ptr<PrivacyHubNotification>>
- sw_notifications_;
- base::WeakPtrFactory<PrivacyHubNotificationController> weak_ptr_factory_{
- this};
+
+ std::unique_ptr<PrivacyHubNotification> microphone_hw_switch_notification_;
};
} // namespace ash
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc b/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc
index 1a107c0..8a0cda6 100644
--- a/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc
+++ b/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc
@@ -12,6 +12,7 @@
#include "ash/public/cpp/test/test_new_window_delegate.h"
#include "ash/public/cpp/test/test_system_tray_client.h"
#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
#include "ash/system/privacy_hub/camera_privacy_switch_controller.h"
#include "ash/system/privacy_hub/microphone_privacy_switch_controller.h"
#include "ash/system/privacy_hub/privacy_hub_controller.h"
@@ -22,6 +23,7 @@
#include "base/test/scoped_feature_list.h"
#include "chromeos/ash/components/dbus/audio/fake_cras_audio_client.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/notification_list.h"
@@ -40,8 +42,7 @@
class RemoveNotificationWaiter : public message_center::MessageCenterObserver {
public:
- explicit RemoveNotificationWaiter(const std::string& notification_id)
- : notification_id_(notification_id) {
+ RemoveNotificationWaiter() {
message_center::MessageCenter::Get()->AddObserver(this);
}
~RemoveNotificationWaiter() override {
@@ -53,13 +54,13 @@
// message_center::MessageCenterObserver:
void OnNotificationRemoved(const std::string& notification_id,
const bool by_user) override {
- if (notification_id == notification_id_) {
+ if (notification_id ==
+ PrivacyHubNotificationController::kCombinedNotificationId) {
run_loop_.Quit();
}
}
private:
- const std::string notification_id_;
base::RunLoop run_loop_;
};
@@ -100,13 +101,12 @@
void TearDown() override { AshTestBase::TearDown(); }
protected:
- const message_center::Notification* GetNotification(
- const char* notification_id =
- PrivacyHubNotificationController::kCombinedNotificationId) const {
+ const message_center::Notification* GetNotification() const {
const message_center::NotificationList::Notifications& notifications =
message_center::MessageCenter::Get()->GetVisibleNotifications();
for (const auto* notification : notifications) {
- if (notification->id() == notification_id) {
+ if (notification->id() ==
+ PrivacyHubNotificationController::kCombinedNotificationId) {
return notification;
}
}
@@ -134,7 +134,7 @@
FakeCrasAudioClient::Get()->SetActiveInputStreamsWithPermission(
{{"CRAS_CLIENT_TYPE_CHROME", 1}});
} else {
- controller_->ShowSensorDisabledNotification(sensor);
+ controller_->ShowSoftwareSwitchNotification(sensor);
}
}
@@ -148,28 +148,26 @@
FakeCrasAudioClient::Get()->SetActiveInputStreamsWithPermission(
{{"CRAS_CLIENT_TYPE_CHROME", 0}});
} else {
- controller_->RemoveSensorDisabledNotification(sensor);
+ controller_->RemoveSoftwareSwitchNotification(sensor);
}
}
void ShowCombinedNotification() {
ShowNotification(Sensor::kCamera);
- controller_->ShowSensorDisabledNotification(Sensor::kMicrophone);
+ ShowNotification(Sensor::kMicrophone);
}
- void ExpectNoNotificationActive() const {
- EXPECT_FALSE(GetNotification());
- EXPECT_FALSE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+ void RemoveCombinedNotification() {
+ RemoveNotification(Sensor::kCamera);
+ RemoveNotification(Sensor::kMicrophone);
}
const base::HistogramTester& histogram_tester() const {
return histogram_tester_;
}
- void WaitUntilNotificationRemoved(const std::string& notification_id) {
- RemoveNotificationWaiter notification_waiter(notification_id);
+ void WaitUntilNotificationRemoved() {
+ RemoveNotificationWaiter notification_waiter;
notification_waiter.Wait();
}
@@ -184,84 +182,106 @@
std::unique_ptr<ash::TestNewWindowDelegateProvider> window_delegate_provider_;
};
-TEST_F(PrivacyHubNotificationControllerTest, ShowCameraNotification) {
- ExpectNoNotificationActive();
+TEST_F(PrivacyHubNotificationControllerTest, CameraNotificationShowAndHide) {
+ EXPECT_FALSE(GetNotification());
+
ShowNotification(Sensor::kCamera);
- EXPECT_TRUE(GetNotification(kPrivacyHubCameraOffNotificationId));
+
+ const message_center::Notification* notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(
+ l10n_util::GetStringUTF16(IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_TITLE),
+ notification_ptr->title());
+
+ RemoveNotification(Sensor::kCamera);
+
+ WaitUntilNotificationRemoved();
+ EXPECT_FALSE(GetNotification());
}
-TEST_F(PrivacyHubNotificationControllerTest, ShowMicrophoneNotification) {
- ExpectNoNotificationActive();
+TEST_F(PrivacyHubNotificationControllerTest,
+ MicrophoneNotificationShowAndHide) {
+ EXPECT_FALSE(GetNotification());
ShowNotification(Sensor::kMicrophone);
- EXPECT_TRUE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+
+ const message_center::Notification* notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_MICROPHONE_MUTED_BY_SW_SWITCH_NOTIFICATION_TITLE),
+ notification_ptr->title());
RemoveNotification(Sensor::kMicrophone);
- WaitUntilNotificationRemoved(
- MicrophonePrivacySwitchController::kNotificationId);
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+
+ WaitUntilNotificationRemoved();
+ EXPECT_FALSE(GetNotification());
}
-TEST_F(PrivacyHubNotificationControllerTest, CombinedNotificationActive) {
- ExpectNoNotificationActive();
+TEST_F(PrivacyHubNotificationControllerTest, CombinedNotificationShowAndHide) {
+ EXPECT_FALSE(GetNotification());
ShowCombinedNotification();
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
- EXPECT_TRUE(GetNotification());
- EXPECT_FALSE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+ const message_center::Notification* notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE),
+ notification_ptr->title());
+
+ RemoveCombinedNotification();
+
+ WaitUntilNotificationRemoved();
+ EXPECT_FALSE(GetNotification());
}
TEST_F(PrivacyHubNotificationControllerTest, CombinedNotificationBuilding) {
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
ShowNotification(Sensor::kMicrophone);
- EXPECT_FALSE(GetNotification());
- EXPECT_FALSE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_TRUE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+
+ const message_center::Notification* notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_MICROPHONE_MUTED_BY_SW_SWITCH_NOTIFICATION_TITLE),
+ notification_ptr->title());
ShowNotification(Sensor::kCamera);
- WaitUntilNotificationRemoved(
- MicrophonePrivacySwitchController::kNotificationId);
- EXPECT_TRUE(GetNotification());
- EXPECT_FALSE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
- // Enable microphone from elsewhere.
+ notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE),
+ notification_ptr->title());
+
RemoveNotification(Sensor::kMicrophone);
- EXPECT_FALSE(GetNotification());
- EXPECT_TRUE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
- // Remove the camera notification as well.
+ notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(
+ l10n_util::GetStringUTF16(IDS_PRIVACY_HUB_CAMERA_OFF_NOTIFICATION_TITLE),
+ notification_ptr->title());
+
RemoveNotification(Sensor::kCamera);
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
- ExpectNoNotificationActive();
+ WaitUntilNotificationRemoved();
+ EXPECT_FALSE(GetNotification());
}
TEST_F(PrivacyHubNotificationControllerTest,
CombinedNotificationClickedButOnlyOneSensorEnabledInSettings) {
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
ShowCombinedNotification();
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
- EXPECT_TRUE(GetNotification());
- EXPECT_FALSE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+ const message_center::Notification* notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE),
+ notification_ptr->title());
ClickOnNotificationBody();
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
// Go to (quick)settings and enable microphone.
RemoveNotification(Sensor::kMicrophone);
@@ -269,111 +289,105 @@
// Since the user clicked on the notification body they acknowledged that
// camera is disabled as well. So don't show that notification even though
// the sensor is still disabled.
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
// Disable camera as well
RemoveNotification(Sensor::kCamera);
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
// Now that no sensor is in use anymore when accessing both again the
// combined notification should show up again.
ShowCombinedNotification();
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
- EXPECT_TRUE(GetNotification());
- EXPECT_FALSE(GetNotification(kPrivacyHubCameraOffNotificationId));
- EXPECT_FALSE(
- GetNotification(MicrophonePrivacySwitchController::kNotificationId));
+ notification_ptr = GetNotification();
+ ASSERT_TRUE(notification_ptr);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE),
+ notification_ptr->title());
}
TEST_F(PrivacyHubNotificationControllerTest, ClickOnNotificationButton) {
- ExpectNoNotificationActive();
- ShowCombinedNotification();
- EXPECT_TRUE(GetNotification());
+ EXPECT_FALSE(GetNotification());
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::
- kPrivacyHubCameraEnabledFromNotificationHistogram,
- true),
- 0);
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::
- kPrivacyHubMicrophoneEnabledFromNotificationHistogram,
- true),
- 0);
+ ShowCombinedNotification();
+
+ EXPECT_TRUE(GetNotification());
+ EXPECT_EQ(0, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::
+ kPrivacyHubCameraEnabledFromNotificationHistogram,
+ true));
+ EXPECT_EQ(0, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::
+ kPrivacyHubMicrophoneEnabledFromNotificationHistogram,
+ true));
ClickOnNotificationButton();
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
-
- ExpectNoNotificationActive();
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::
- kPrivacyHubCameraEnabledFromNotificationHistogram,
- true),
- 1);
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::
- kPrivacyHubMicrophoneEnabledFromNotificationHistogram,
- true),
- 1);
+ EXPECT_FALSE(GetNotification());
+ EXPECT_EQ(1, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::
+ kPrivacyHubCameraEnabledFromNotificationHistogram,
+ true));
+ EXPECT_EQ(1, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::
+ kPrivacyHubMicrophoneEnabledFromNotificationHistogram,
+ true));
}
TEST_F(PrivacyHubNotificationControllerTest, ClickOnSecondNotificationButton) {
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
+
ShowCombinedNotification();
+
EXPECT_TRUE(GetNotification());
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::kPrivacyHubOpenedHistogram,
- privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification),
- 0);
- EXPECT_EQ(GetSystemTrayClient()->show_os_settings_privacy_hub_count(), 0);
+ EXPECT_EQ(
+ 0, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::kPrivacyHubOpenedHistogram,
+ privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification));
+ EXPECT_EQ(0, GetSystemTrayClient()->show_os_settings_privacy_hub_count());
ClickOnNotificationButton(1);
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
+ EXPECT_FALSE(GetNotification());
- ExpectNoNotificationActive();
-
- EXPECT_EQ(GetSystemTrayClient()->show_os_settings_privacy_hub_count(), 1);
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::kPrivacyHubOpenedHistogram,
- privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification),
- 1);
+ EXPECT_EQ(1, GetSystemTrayClient()->show_os_settings_privacy_hub_count());
+ EXPECT_EQ(
+ 1, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::kPrivacyHubOpenedHistogram,
+ privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification));
}
TEST_F(PrivacyHubNotificationControllerTest, ClickOnNotificationBody) {
- ExpectNoNotificationActive();
- ShowCombinedNotification();
- EXPECT_TRUE(GetNotification());
+ EXPECT_FALSE(GetNotification());
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::kPrivacyHubOpenedHistogram,
- privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification),
- 0);
+ ShowCombinedNotification();
+
+ EXPECT_TRUE(GetNotification());
+ EXPECT_EQ(
+ 0, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::kPrivacyHubOpenedHistogram,
+ privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification));
ClickOnNotificationBody();
- WaitUntilNotificationRemoved(kPrivacyHubCameraOffNotificationId);
-
- ExpectNoNotificationActive();
+ EXPECT_FALSE(GetNotification());
}
TEST_F(PrivacyHubNotificationControllerTest, OpenPrivacyHubSettingsPage) {
- EXPECT_EQ(GetSystemTrayClient()->show_os_settings_privacy_hub_count(), 0);
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::kPrivacyHubOpenedHistogram,
- privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification),
- 0);
+ EXPECT_EQ(0, GetSystemTrayClient()->show_os_settings_privacy_hub_count());
+ EXPECT_EQ(
+ 0, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::kPrivacyHubOpenedHistogram,
+ privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification));
PrivacyHubNotificationController::OpenPrivacyHubSettingsPage();
- EXPECT_EQ(GetSystemTrayClient()->show_os_settings_privacy_hub_count(), 1);
- EXPECT_EQ(histogram_tester().GetBucketCount(
- privacy_hub_metrics::kPrivacyHubOpenedHistogram,
- privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification),
- 1);
+ EXPECT_EQ(1, GetSystemTrayClient()->show_os_settings_privacy_hub_count());
+ EXPECT_EQ(
+ 1, histogram_tester().GetBucketCount(
+ privacy_hub_metrics::kPrivacyHubOpenedHistogram,
+ privacy_hub_metrics::PrivacyHubNavigationOrigin::kNotification));
}
TEST_F(PrivacyHubNotificationControllerTest, OpenPrivacyHubSupportPage) {
@@ -382,17 +396,17 @@
auto test_sensor = [histogram_tester = &histogram_tester()](
Sensor privacy_hub_sensor,
PrivacyHubLearnMoreSensor lean_more_sensor) {
- EXPECT_EQ(histogram_tester->GetBucketCount(
+ EXPECT_EQ(0,
+ histogram_tester->GetBucketCount(
privacy_hub_metrics::kPrivacyHubLearnMorePageOpenedHistogram,
- lean_more_sensor),
- 0);
+ lean_more_sensor));
PrivacyHubNotificationController::OpenSupportUrl(privacy_hub_sensor);
- EXPECT_EQ(histogram_tester->GetBucketCount(
+ EXPECT_EQ(1,
+ histogram_tester->GetBucketCount(
privacy_hub_metrics::kPrivacyHubLearnMorePageOpenedHistogram,
- lean_more_sensor),
- 1);
+ lean_more_sensor));
};
EXPECT_CALL(*new_window_delegate(), OpenUrl).Times(2);
diff --git a/ash/system/privacy_hub/privacy_hub_notification_unittest.cc b/ash/system/privacy_hub/privacy_hub_notification_unittest.cc
index 2522b0a..bc58dd80 100644
--- a/ash/system/privacy_hub/privacy_hub_notification_unittest.cc
+++ b/ash/system/privacy_hub/privacy_hub_notification_unittest.cc
@@ -114,7 +114,8 @@
SensorDisabledNotificationDelegate::SensorSet{
SensorDisabledNotificationDelegate::Sensor::kMicrophone},
IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_TITLE,
- IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_BUTTON,
+ std::vector<int>{
+ IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_BUTTON},
std::vector<int>{
IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE,
IDS_PRIVACY_HUB_MICROPHONE_AND_CAMERA_OFF_NOTIFICATION_MESSAGE_WITH_ONE_APP_NAME,
@@ -272,26 +273,6 @@
EXPECT_FALSE(GetPopupNotification());
}
-TEST_F(PrivacyHubNotificationTest, AddButton) {
- notification().Show();
-
- EXPECT_EQ(GetNotification()->rich_notification_data().buttons.size(), 1u);
-
- int second_button_clicked = 0;
- notification().SetSecondButton(
- base::BindLambdaForTesting(
- [&second_button_clicked]() { second_button_clicked++; }),
- IDS_PRIVACY_HUB_OPEN_SETTINGS_PAGE_BUTTON);
-
- notification().Update();
- message_center::Notification* test_notification = GetNotification();
- ASSERT_EQ(test_notification->rich_notification_data().buttons.size(), 2u);
-
- EXPECT_EQ(second_button_clicked, 0);
- test_notification->delegate()->Click(1, absl::nullopt);
- EXPECT_EQ(second_button_clicked, 1);
-}
-
TEST_F(PrivacyHubNotificationTest, WithApps) {
// No apps -> generic notification text.
notification().Show();
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc
index cc31c682..6a97d5f 100644
--- a/chrome/browser/ui/ash/media_client_impl.cc
+++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -280,7 +280,7 @@
ash::PrivacyHubNotificationDescriptor{
ash::SensorDisabledNotificationDelegate::SensorSet{},
IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_TITLE,
- IDS_ASH_LEARN_MORE,
+ std::vector<int>{IDS_ASH_LEARN_MORE},
std::vector<int>{
IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_MESSAGE},
base::MakeRefCounted<