// 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 "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_;
}
private:
// Updates privacy indicators after camera mute state changed.
void UpdateForCameraMuteStateChanged();
// 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;
};
// 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_