Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement systemPreferences.getMediaAccessStatus() on Windows #24312

Merged
merged 1 commit into from Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/api/system-preferences.md
Expand Up @@ -416,7 +416,7 @@ This API itself will not protect your user data; rather, it is a mechanism to al

Returns `Boolean` - `true` if the current process is a trusted accessibility client and `false` if it is not.

### `systemPreferences.getMediaAccessStatus(mediaType)` _macOS_
### `systemPreferences.getMediaAccessStatus(mediaType)` _Windows_ _macOS_

* `mediaType` String - Can be `microphone`, `camera` or `screen`.

Expand All @@ -426,6 +426,9 @@ This user consent was not required on macOS 10.13 High Sierra or lower so this m
macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access.
macOS 10.15 Catalina or higher requires consent for `screen` access.

Windows 10 has a global setting controlling `microphone` and `camera` access for all win32 applications.
It will always return `granted` for `screen` and for all media types on older versions of Windows.

### `systemPreferences.askForMediaAccess(mediaType)` _macOS_

* `mediaType` String - the type of media being requested; can be `microphone`, `camera`.
Expand Down
4 changes: 2 additions & 2 deletions shell/browser/api/electron_api_system_preferences.cc
Expand Up @@ -73,6 +73,8 @@ void SystemPreferences::BuildPrototype(
#if defined(OS_WIN) || defined(OS_MACOSX)
.SetMethod("getColor", &SystemPreferences::GetColor)
.SetMethod("getAccentColor", &SystemPreferences::GetAccentColor)
.SetMethod("getMediaAccessStatus",
&SystemPreferences::GetMediaAccessStatus)
#endif

#if defined(OS_WIN)
Expand Down Expand Up @@ -112,8 +114,6 @@ void SystemPreferences::BuildPrototype(
.SetMethod("promptTouchID", &SystemPreferences::PromptTouchID)
.SetMethod("isTrustedAccessibilityClient",
&SystemPreferences::IsTrustedAccessibilityClient)
.SetMethod("getMediaAccessStatus",
&SystemPreferences::GetMediaAccessStatus)
.SetMethod("askForMediaAccess", &SystemPreferences::AskForMediaAccess)
#endif
.SetMethod("isInvertedColorScheme",
Expand Down
8 changes: 4 additions & 4 deletions shell/browser/api/electron_api_system_preferences.h
Expand Up @@ -49,6 +49,10 @@ class SystemPreferences : public gin_helper::EventEmitter<SystemPreferences>
std::string GetAccentColor();
std::string GetColor(gin_helper::ErrorThrower thrower,
const std::string& color);
// TODO(codebytere): Write tests for these methods once we
// are running tests on a Mojave machine
std::string GetMediaAccessStatus(const std::string& media_type,
gin_helper::Arguments* args);
#endif
#if defined(OS_WIN)
bool IsAeroGlassEnabled();
Expand Down Expand Up @@ -99,10 +103,6 @@ class SystemPreferences : public gin_helper::EventEmitter<SystemPreferences>

static bool IsTrustedAccessibilityClient(bool prompt);

// TODO(codebytere): Write tests for these methods once we
// are running tests on a Mojave machine
std::string GetMediaAccessStatus(const std::string& media_type,
gin_helper::Arguments* args);
v8::Local<v8::Promise> AskForMediaAccess(v8::Isolate* isolate,
const std::string& media_type);

Expand Down
66 changes: 66 additions & 0 deletions shell/browser/api/electron_api_system_preferences_win.cc
Expand Up @@ -3,10 +3,13 @@
// found in the LICENSE file.

#include <dwmapi.h>
#include <windows.devices.enumeration.h>
#include <wrl/client.h>
#include <iomanip>

#include "shell/browser/api/electron_api_system_preferences.h"

#include "base/win/core_winrt_util.h"
#include "base/win/wrapped_window_proc.h"
#include "shell/common/color_util.h"
#include "ui/base/win/shell.h"
Expand All @@ -20,6 +23,51 @@ namespace {
const wchar_t kSystemPreferencesWindowClass[] =
L"Electron_SystemPreferencesHostWindow";

using ABI::Windows::Devices::Enumeration::DeviceAccessStatus;
using ABI::Windows::Devices::Enumeration::DeviceClass;
using ABI::Windows::Devices::Enumeration::IDeviceAccessInformation;
using ABI::Windows::Devices::Enumeration::IDeviceAccessInformationStatics;
using Microsoft::WRL::ComPtr;

DeviceAccessStatus GetDeviceAccessStatus(DeviceClass device_class) {
ComPtr<IDeviceAccessInformationStatics> dev_access_info_statics;
HRESULT hr = base::win::GetActivationFactory<
IDeviceAccessInformationStatics,
RuntimeClass_Windows_Devices_Enumeration_DeviceAccessInformation>(
&dev_access_info_statics);
if (FAILED(hr)) {
VLOG(1) << "IDeviceAccessInformationStatics failed: " << hr;
return DeviceAccessStatus::DeviceAccessStatus_Allowed;
}

ComPtr<IDeviceAccessInformation> dev_access_info;
hr = dev_access_info_statics->CreateFromDeviceClass(device_class,
&dev_access_info);
if (FAILED(hr)) {
VLOG(1) << "IDeviceAccessInformation failed: " << hr;
return DeviceAccessStatus::DeviceAccessStatus_Allowed;
}

auto status = DeviceAccessStatus::DeviceAccessStatus_Unspecified;
dev_access_info->get_CurrentStatus(&status);
return status;
}

std::string ConvertDeviceAccessStatus(DeviceAccessStatus value) {
switch (value) {
case DeviceAccessStatus::DeviceAccessStatus_Unspecified:
return "not-determined";
case DeviceAccessStatus::DeviceAccessStatus_Allowed:
return "granted";
case DeviceAccessStatus::DeviceAccessStatus_DeniedBySystem:
return "restricted";
case DeviceAccessStatus::DeviceAccessStatus_DeniedByUser:
return "denied";
default:
return "unknown";
}
}

} // namespace

namespace api {
Expand Down Expand Up @@ -117,6 +165,24 @@ std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
return ToRGBHex(color_utils::GetSysSkColor(id));
}

std::string SystemPreferences::GetMediaAccessStatus(
const std::string& media_type,
gin_helper::Arguments* args) {
if (media_type == "camera") {
return ConvertDeviceAccessStatus(
GetDeviceAccessStatus(DeviceClass::DeviceClass_VideoCapture));
} else if (media_type == "microphone") {
return ConvertDeviceAccessStatus(
GetDeviceAccessStatus(DeviceClass::DeviceClass_AudioCapture));
} else if (media_type == "screen") {
return ConvertDeviceAccessStatus(
DeviceAccessStatus::DeviceAccessStatus_Allowed);
} else {
args->ThrowError("Invalid media type");
return std::string();
}
}

void SystemPreferences::InitializeWindow() {
invertered_color_scheme_ = IsInvertedColorScheme();
high_contrast_color_scheme_ = IsHighContrastColorScheme();
Expand Down
2 changes: 1 addition & 1 deletion spec-main/api-system-preferences-spec.ts
Expand Up @@ -269,7 +269,7 @@ describe('systemPreferences module', () => {
});
});

ifdescribe(process.platform === 'darwin')('systemPreferences.getMediaAccessStatus(mediaType)', () => {
ifdescribe(['win32', 'darwin'].includes(process.platform))('systemPreferences.getMediaAccessStatus(mediaType)', () => {
const statuses = ['not-determined', 'granted', 'denied', 'restricted', 'unknown'];

it('returns an access status for a camera access request', () => {
Expand Down