blob: 296397f899989510cfd534fff182476dbf184140 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/permissions/system/system_permission_settings.h"
#include <memory>
#include "base/mac/mac_util.h"
#include "base/notreached.h"
#include "base/scoped_observation.h"
#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
#include "chrome/browser/web_applications/os_integration/mac/app_shim_registry.h"
#include "chrome/browser/web_applications/os_integration/mac/web_app_shortcut_mac.h"
#include "chrome/browser/web_applications/web_app_tab_helper.h"
#include "chrome/common/chrome_features.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
static_assert(BUILDFLAG(IS_MAC));
namespace {
bool denied(system_media_permissions::SystemPermission permission) {
return system_media_permissions::SystemPermission::kDenied == permission;
}
bool prompt(system_media_permissions::SystemPermission permission) {
return system_media_permissions::SystemPermission::kNotDetermined ==
permission;
}
bool allowed(system_media_permissions::SystemPermission permission) {
return system_media_permissions::SystemPermission::kAllowed == permission;
}
} // namespace
class SystemPermissionSettingsImpl
: public SystemPermissionSettings,
public device::GeolocationSystemPermissionManager::PermissionObserver {
public:
SystemPermissionSettingsImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* geolocation_system_permission_manager =
device::GeolocationSystemPermissionManager::GetInstance();
CHECK(geolocation_system_permission_manager);
observation_.Observe(geolocation_system_permission_manager);
}
~SystemPermissionSettingsImpl() override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
FlushGeolocationCallbacks();
}
bool CanPrompt(ContentSettingsType type) const override {
switch (type) {
case ContentSettingsType::MEDIASTREAM_CAMERA:
return prompt(
system_media_permissions::CheckSystemVideoCapturePermission());
case ContentSettingsType::MEDIASTREAM_MIC:
return prompt(
system_media_permissions::CheckSystemAudioCapturePermission());
case ContentSettingsType::GEOLOCATION:
return device::GeolocationSystemPermissionManager::GetInstance()
->GetSystemPermission() ==
device::LocationSystemPermissionStatus::kNotDetermined;
default:
return false;
}
}
bool IsDeniedImpl(ContentSettingsType type) const override {
switch (type) {
case ContentSettingsType::MEDIASTREAM_CAMERA:
return denied(
system_media_permissions::CheckSystemVideoCapturePermission());
case ContentSettingsType::MEDIASTREAM_MIC:
return denied(
system_media_permissions::CheckSystemAudioCapturePermission());
case ContentSettingsType::GEOLOCATION:
return device::GeolocationSystemPermissionManager::GetInstance()
->GetSystemPermission() ==
device::LocationSystemPermissionStatus::kDenied;
default:
return false;
}
}
bool IsAllowedImpl(ContentSettingsType type) const override {
switch (type) {
case ContentSettingsType::MEDIASTREAM_CAMERA:
return allowed(
system_media_permissions::CheckSystemVideoCapturePermission());
case ContentSettingsType::MEDIASTREAM_MIC:
return allowed(
system_media_permissions::CheckSystemAudioCapturePermission());
case ContentSettingsType::GEOLOCATION:
return device::GeolocationSystemPermissionManager::GetInstance()
->GetSystemPermission() ==
device::LocationSystemPermissionStatus::kAllowed;
default:
return true;
}
}
void OpenSystemSettings(content::WebContents* web_contents,
ContentSettingsType type) const override {
switch (type) {
case ContentSettingsType::NOTIFICATIONS: {
const webapps::AppId* app_id =
web_app::WebAppTabHelper::GetAppId(web_contents);
if (!app_id) {
return;
}
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kNotifications,
web_app::GetBundleIdentifierForShim(*app_id));
return;
}
case ContentSettingsType::MEDIASTREAM_CAMERA: {
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kPrivacySecurity_Camera);
return;
}
case ContentSettingsType::MEDIASTREAM_MIC: {
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kPrivacySecurity_Microphone);
return;
}
case ContentSettingsType::GEOLOCATION: {
device::GeolocationSystemPermissionManager::GetInstance()
->OpenSystemPermissionSetting();
return;
}
default:
NOTREACHED();
}
}
void Request(ContentSettingsType type,
SystemPermissionResponseCallback callback) override {
switch (type) {
case ContentSettingsType::MEDIASTREAM_CAMERA: {
system_media_permissions::RequestSystemVideoCapturePermission(
std::move(callback));
return;
}
case ContentSettingsType::MEDIASTREAM_MIC: {
system_media_permissions::RequestSystemAudioCapturePermission(
std::move(callback));
return;
}
case ContentSettingsType::GEOLOCATION: {
geolocation_callbacks_.push_back(std::move(callback));
// The system permission prompt is modal and requires a user decision
// (Allow or Deny) before it can be dismissed.
if (geolocation_callbacks_.size() == 1u) {
device::GeolocationSystemPermissionManager::GetInstance()
->RequestSystemPermission();
}
return;
}
default:
std::move(callback).Run();
NOTREACHED();
}
}
// device::GeolocationSystemPermissionManager::PermissionObserver
// implementation.
void OnSystemPermissionUpdated(
device::LocationSystemPermissionStatus new_status) override {
FlushGeolocationCallbacks();
}
private:
void FlushGeolocationCallbacks() {
auto callbacks = std::move(geolocation_callbacks_);
for (auto& cb : callbacks) {
std::move(cb).Run();
}
}
std::vector<SystemPermissionResponseCallback> geolocation_callbacks_;
base::ScopedObservation<
device::GeolocationSystemPermissionManager,
device::GeolocationSystemPermissionManager::PermissionObserver>
observation_{this};
};
std::unique_ptr<SystemPermissionSettings>
SystemPermissionSettings::CreateImpl() {
return std::make_unique<SystemPermissionSettingsImpl>();
}