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 #24275

Merged
merged 1 commit into from Jun 25, 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is specific for win32 applications should we safety check if for APPX / Window Store builds?

Copy link
Contributor Author

@miniak miniak Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The system API returns the global value, it should work fine. Electron Window Store app is still Win32.

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
4 changes: 2 additions & 2 deletions shell/browser/api/electron_api_system_preferences.h
Expand Up @@ -49,6 +49,8 @@ class SystemPreferences : public gin_helper::EventEmitter<SystemPreferences>
std::string GetAccentColor();
std::string GetColor(gin_helper::ErrorThrower thrower,
const std::string& color);
std::string GetMediaAccessStatus(const std::string& media_type,
gin_helper::Arguments* args);
#endif
#if defined(OS_WIN)
bool IsAeroGlassEnabled();
Expand Down Expand Up @@ -99,8 +101,6 @@ class SystemPreferences : public gin_helper::EventEmitter<SystemPreferences>

static bool IsTrustedAccessibilityClient(bool prompt);

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);
miniak marked this conversation as resolved.
Show resolved Hide resolved
} else {
args->ThrowError("Invalid media type");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not originating from this PR but when we have a unknown state in the docs, why do we want to throw an error ? seem to do it for macOS as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deepak1556 The return type can have unknown, the media_type argument can't be unknown

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an unknown media type why can't the return type by unknown, the current system calls both on windows and macOS never return an unknown state, the value is being unused. I wouldn't mind if this state wasn't documented but it is :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to bring this up with api-WG

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can address it in a separate PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

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