[go: nahoru, domu]

blob: 20bd8d86122f279be4eed344eed428c262d2769d [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "remoting/host/mac/permission_utils.h"
#import <AVFoundation/AVFoundation.h>
#import <Cocoa/Cocoa.h>
#include "base/apple/foundation_util.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/sys_string_conversions.h"
#import "base/task/sequenced_task_runner.h"
#include "base/task/sequenced_task_runner.h"
#import "base/task/single_thread_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "remoting/base/string_resources.h"
#include "ui/base/cocoa/permissions_utils.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_mac.h"
namespace {
constexpr int kMinDialogWidthPx = 650;
// The name of the host service as it appears in the system's Accessibility
// permission dialog.
constexpr NSString* kHostServiceName = @"ChromeRemoteDesktopHost";
void ShowAccessibilityPermissionDialog() {
NSAlert* alert = [[NSAlert alloc] init];
alert.messageText =
l10n_util::GetNSStringF(IDS_ACCESSIBILITY_PERMISSION_DIALOG_TITLE,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
alert.informativeText = l10n_util::GetNSStringF(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_BODY_TEXT,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
l10n_util::GetStringUTF16(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_OPEN_BUTTON),
base::SysNSStringToUTF16(kHostServiceName));
[alert
addButtonWithTitle:l10n_util::GetNSString(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_OPEN_BUTTON)];
[alert addButtonWithTitle:
l10n_util::GetNSString(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_NOT_NOW_BUTTON)];
// Increase the alert width so the title doesn't wrap and the body text is
// less scrunched. Note that we only want to set a min-width, we don't
// want to shrink the dialog if it is already larger than our min value.
NSWindow* alert_window = alert.window;
NSRect frame = alert_window.frame;
if (frame.size.width < kMinDialogWidthPx) {
frame.size.width = kMinDialogWidthPx;
}
[alert_window setFrame:frame display:YES];
alert.alertStyle = NSAlertStyleWarning;
[alert_window makeKeyWindow];
if ([alert runModal] == NSAlertFirstButtonReturn) {
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kPrivacySecurity_Accessibility);
}
}
void ShowScreenRecordingPermissionDialog() {
NSAlert* alert = [[NSAlert alloc] init];
alert.messageText =
l10n_util::GetNSStringF(IDS_SCREEN_RECORDING_PERMISSION_DIALOG_TITLE,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
alert.informativeText = l10n_util::GetNSStringF(
IDS_SCREEN_RECORDING_PERMISSION_DIALOG_BODY_TEXT,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
l10n_util::GetStringUTF16(
IDS_SCREEN_RECORDING_PERMISSION_DIALOG_OPEN_BUTTON),
base::SysNSStringToUTF16(kHostServiceName));
[alert addButtonWithTitle:
l10n_util::GetNSString(
IDS_SCREEN_RECORDING_PERMISSION_DIALOG_OPEN_BUTTON)];
[alert addButtonWithTitle:
l10n_util::GetNSString(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_NOT_NOW_BUTTON)];
// Increase the alert width so the title doesn't wrap and the body text is
// less scrunched. Note that we only want to set a min-width, we don't
// want to shrink the dialog if it is already larger than our min value.
NSWindow* alert_window = alert.window;
NSRect frame = alert_window.frame;
if (frame.size.width < kMinDialogWidthPx) {
frame.size.width = kMinDialogWidthPx;
}
[alert_window setFrame:frame display:YES];
alert.alertStyle = NSAlertStyleWarning;
[alert_window makeKeyWindow];
if ([alert runModal] == NSAlertFirstButtonReturn) {
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kPrivacySecurity_ScreenRecording);
}
}
} // namespace
namespace remoting::mac {
bool CanInjectInput() {
return AXIsProcessTrusted();
}
bool CanRecordScreen() {
return ui::IsScreenCaptureAllowed();
}
// macOS requires an additional runtime permission for injecting input using
// CGEventPost (we use this in our input injector for Mac). This method will
// request that the user enable this permission for us if they are on an
// affected version and the permission has not already been approved.
void PromptUserForAccessibilityPermissionIfNeeded(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
if (CanInjectInput()) {
return;
}
LOG(WARNING) << "AXIsProcessTrusted returned false, requesting "
<< "permission from user to allow input injection.";
task_runner->PostTask(FROM_HERE,
base::BindOnce(&ShowAccessibilityPermissionDialog));
}
// macOS requires an additional runtime permission for capturing the screen.
// This method will request that the user enable this permission for us if they
// are on an affected version and the permission has not already been approved.
void PromptUserForScreenRecordingPermissionIfNeeded(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
if (CanRecordScreen()) {
return;
}
LOG(WARNING) << "CanRecordScreen returned false, requesting permission "
<< "from user to allow screen recording.";
task_runner->PostTask(FROM_HERE,
base::BindOnce(&ShowScreenRecordingPermissionDialog));
}
void PromptUserToChangeTrustStateIfNeeded(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
PromptUserForAccessibilityPermissionIfNeeded(task_runner);
PromptUserForScreenRecordingPermissionIfNeeded(task_runner);
}
bool CanCaptureAudio() {
AVAuthorizationStatus auth_status =
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
return auth_status == AVAuthorizationStatusAuthorized;
}
void RequestAudioCapturePermission(base::OnceCallback<void(bool)> callback) {
auto task_runner = base::SequencedTaskRunner::GetCurrentDefault();
__block auto block_callback = std::move(callback);
[AVCaptureDevice
requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(BOOL granted) {
task_runner->PostTask(
FROM_HERE,
base::BindOnce(std::move(block_callback), granted));
}];
return;
}
} // namespace remoting::mac