1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
ash / system / privacy / privacy_indicators_controller.h [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_PRIVACY_PRIVACY_INDICATORS_CONTROLLER_H_
#define ASH_SYSTEM_PRIVACY_PRIVACY_INDICATORS_CONTROLLER_H_
#include <optional>
#include <string>
#include "ash/ash_export.h"
#include "base/functional/callback_forward.h"
#include "base/timer/timer.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
namespace ash {
// An interface for the delegate of the privacy indicators notification,
// handling launching the app and its settings. Clients that use privacy
// indicators should provide this delegate when calling the privacy indicators
// controller API so that the API can add correct buttons to the notification
// based on the callbacks provided and appropriate actions are performed when
// clicking the buttons.
class ASH_EXPORT PrivacyIndicatorsNotificationDelegate
: public message_center::NotificationDelegate {
public:
explicit PrivacyIndicatorsNotificationDelegate(
std::optional<base::RepeatingClosure> launch_settings_callback =
std::nullopt);
PrivacyIndicatorsNotificationDelegate(
const PrivacyIndicatorsNotificationDelegate&) = delete;
PrivacyIndicatorsNotificationDelegate& operator=(
const PrivacyIndicatorsNotificationDelegate&) = delete;
const std::optional<base::RepeatingClosure>& launch_settings_callback()
const {
return launch_settings_callback_;
}
void SetLaunchSettingsCallback(
const base::RepeatingClosure& launch_settings_callback);
// message_center::NotificationDelegate:
void Click(const std::optional<int>& button_index,
const std::optional<std::u16string>& reply) override;
protected:
~PrivacyIndicatorsNotificationDelegate() override;
private:
// Callback for clicking the launch settings button.
std::optional<base::RepeatingClosure> launch_settings_callback_;
};
// This enum contains all the sources that use privacy indicators. This enum is
// used for metrics collection. Note to keep in sync with enum in
// tools/metrics/histograms/enums.xml.
enum class PrivacyIndicatorsSource {
kApps = 0,
kLinuxVm = 1,
kScreenCapture = 2,
kMaxValue = kScreenCapture
};
// Get the id of the privacy indicators notification associated with `app_id`.
std::string ASH_EXPORT
GetPrivacyIndicatorsNotificationId(const std::string& app_id);
// Struct that stores info of an app that is being tracked by privacy
// indicators.
struct PrivacyIndicatorsAppInfo {
PrivacyIndicatorsAppInfo();
PrivacyIndicatorsAppInfo(PrivacyIndicatorsAppInfo&&);
PrivacyIndicatorsAppInfo& operator=(PrivacyIndicatorsAppInfo&&) = default;
~PrivacyIndicatorsAppInfo();
std::optional<std::u16string> app_name;
scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate;
};
// A controller that manages the logic of modifying the tray item privacy
// indicator dot and the privacy indicators notification when camera/microphone
// access state changes.
class ASH_EXPORT PrivacyIndicatorsController
: public CrasAudioHandler::AudioObserver,
public media::CameraPrivacySwitchObserver {
public:
PrivacyIndicatorsController();
PrivacyIndicatorsController(const PrivacyIndicatorsController&) = delete;
PrivacyIndicatorsController& operator=(const PrivacyIndicatorsController&) =
delete;
~PrivacyIndicatorsController() override;
// Returns the singleton instance.
static PrivacyIndicatorsController* Get();
// Updates privacy indicators, including:
// * Updates camera and microphone access indicators for
// `PrivacyIndicatorsTrayItemView`(s) across all status area widgets.
// * Adds, updates, or removes the privacy notification associated with the
// given `app_id`. The given scoped_refptr for `delegate` will be passed as
// a parameter for the function creating the privacy indicators
// notification.
// Note that if camera/microphone are muted, privacy indicators will not
// indicate its usage via the tray item indicator dot and the notification.
void UpdatePrivacyIndicators(
const std::string& app_id,
std::optional<std::u16string> app_name,
bool is_camera_used,
bool is_microphone_used,
scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate,
PrivacyIndicatorsSource source);
// media::CameraPrivacySwitchObserver:
void OnCameraHWPrivacySwitchStateChanged(
const std::string& device_id,
cros::mojom::CameraPrivacySwitchState state) override;
void OnCameraSWPrivacySwitchStateChanged(
cros::mojom::CameraPrivacySwitchState state) override;
// CrasAudioHandler::AudioObserver:
void OnInputMuteChanged(
bool mute_on,
CrasAudioHandler::InputMuteChangeMethod method) override;
// Specifies whether camera/microphone is in use by at least one app.
bool IsCameraUsed() const;
bool IsMicrophoneUsed() const;
const std::map<std::string, PrivacyIndicatorsAppInfo>& apps_using_camera()
const {
return apps_using_camera_;
}
const std::map<std::string, PrivacyIndicatorsAppInfo>& apps_using_microphone()
const {
return apps_using_microphone_;
}
// A minimum delay before privacy indicator disappears.
static constexpr base::TimeDelta kPrivacyIndicatorsMinimumHoldDuration =
base::Seconds(4);
// A delay before the privacy indicator disappears if they were previously
// used longer than `kPrivacyIndicatorsMinimumHoldDuration`.
static constexpr base::TimeDelta kPrivacyIndicatorsHoldAfterUseDuration =
base::Seconds(1);
private:
// Updates privacy indicators after camera mute state changed.
void UpdateForCameraMuteStateChanged();
// `indicators_hiding_delay_timer_` is triggering this function when the timer
// expires.
void TriggerPrivacyIndicators(
bool is_camera_used,
bool is_microphone_used,
bool is_new_app,
bool was_camera_in_use,
bool was_microphone_in_use,
const std::string& app_id,
std::optional<std::u16string> app_name,
scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate);
// If neither camera nor microphone is in use, calculates the delay for the
// hiding timer.
base::TimeDelta CalculateIndicatorsDelayTime() const;
// If another app is using a camera and the new app tries to use the same
// camera but fails, returns true to indicate that the privacy indicators
// should be skipped.
bool ShouldSkipShowPrivacyIndicators(bool is_camera_used,
bool is_microphone_used,
bool is_new_app,
bool was_camera_in_use) const;
// Stores the app(s) info that are currently accessing camera/microphone. The
// key represents the app id.
std::map<std::string, PrivacyIndicatorsAppInfo> apps_using_camera_;
std::map<std::string, PrivacyIndicatorsAppInfo> apps_using_microphone_;
// This keeps track of the current Camera Privacy Switch state.
// Updated via `OnCameraHWPrivacySwitchStateChanged()` and
// `OnCameraSWPrivacySwitchStateChanged()` We use these variables since
// fetching this directly through `media::CameraHalDispatcherImpl` would
// otherwise need an asynchronous call.
bool camera_muted_by_hardware_switch_ = false;
bool camera_muted_by_software_switch_ = false;
// The time when the privacy indicator was active.
base::TimeTicks privacy_indicator_time_;
// The most recent state when the privacy indicator was active.
std::pair<bool /*camera_state*/, bool /*microphone_state*/>
recent_active_state_ = {false, false};
// A timer to delay hiding a privacy indicator.
base::OneShotTimer indicator_hiding_delay_timer_;
};
// 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_