0

Add shortcut to toggle camera access (behind flag)

This CL creates a new shortcut that toggles the setting "Camera access"
in the "Privacy controls" section of ChromeOS Settings. When the setting
is enabled or disabled, a toast message is displayed.

Example of toast message:
https://screenshot.googleplex.com/4FVYuo4rpArdez6

There is a special case where camera access may be force disabled, due
to an admin remoting into a user's ChromeOS instance. In this case,
the shortcut has no effect, and a toast message is shown indicating
that the setting cannot be changed.

Bug: b/383772675
Change-Id: I64fa7e8e0de2427e23f4bae368c64a9166c0ec1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6092031
Commit-Queue: Camden Bickel <cambickel@google.com>
Reviewed-by: Jimmy Gong <jimmyxgong@chromium.org>
Reviewed-by: Alex Gough <ajgo@chromium.org>
Reviewed-by: David Padlipsky <dpad@google.com>
Reviewed-by: Jiaming Cheng <jiamingc@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1401983}
This commit is contained in:
Cam Bickel
2025-01-03 15:19:00 -08:00
committed by Chromium LUCI CQ
parent 5cb7edb85a
commit 4dca0cd88d
21 changed files with 122 additions and 3 deletions

@ -51,6 +51,8 @@
#include "ash/system/notification_center/notification_center_tray.h"
#include "ash/system/palette/palette_tray.h"
#include "ash/system/power/power_button_controller.h"
#include "ash/system/privacy_hub/camera_privacy_switch_controller.h"
#include "ash/system/privacy_hub/privacy_hub_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/time/calendar_metrics.h"
#include "ash/system/time/calendar_model.h"
@ -146,6 +148,9 @@ constexpr char kAssistantErrorToastId[] = "assistant_error";
// Toast ID for the notification center tray "No notifications" toast.
constexpr char kNotificationCenterTrayNoNotificationsToastId[] =
"notification_center_tray_toast_ids.no_notifications";
// Toast IDs for the Toggle Camera Allowed shortcut.
constexpr char kToggleCameraToastId[] = "toggle_camera_toast";
constexpr char kCameraForceDisabledToastId[] = "camera_force_disabled_toast";
// These values are written to logs. New enum values can be added, but existing
// enums must never be renumbered or deleted and reused.
@ -1438,6 +1443,54 @@ void ToggleCalendar() {
calendar_metrics::CalendarEventSource::kKeyboard);
}
void ToggleCameraAllowed() {
if (!features::IsToggleCameraShortcutEnabled()) {
return;
}
auto* pref_service =
Shell::Get()->session_controller()->GetActivePrefService();
if (!pref_service) {
return;
}
PrivacyHubController* privacy_hub_controller =
Shell::Get()->privacy_hub_controller();
if (!privacy_hub_controller) {
return;
}
CameraPrivacySwitchController* camera_privacy_switch_controller =
privacy_hub_controller->camera_controller();
if (!camera_privacy_switch_controller) {
return;
}
// Camera access may be force-disabled in cases where an admin is using Remote
// Desktop to control a user's device. This shortcut should respect that
// setting and should not enable the camera in such situations.
if (camera_privacy_switch_controller->IsCameraAccessForceDisabled()) {
ShowToast(kCameraForceDisabledToastId,
ToastCatalogName::kCameraForceDisabled,
l10n_util::GetStringUTF16(IDS_ASH_CAMERA_ACCESS_DISABLED));
return;
}
// Toggle the value of the pref.
const bool wasCameraPreviouslyAllowed =
pref_service->GetBoolean(prefs::kUserCameraAllowed);
const bool isCameraNowAllowed = !wasCameraPreviouslyAllowed;
pref_service->SetBoolean(prefs::kUserCameraAllowed, isCameraNowAllowed);
if (isCameraNowAllowed) {
ShowToast(kToggleCameraToastId, ToastCatalogName::kCameraNowAllowed,
l10n_util::GetStringUTF16(IDS_ASH_CAMERA_NOW_ALLOWED));
} else {
ShowToast(kToggleCameraToastId, ToastCatalogName::kCameraNowAllowed,
l10n_util::GetStringUTF16(IDS_ASH_CAMERA_NOW_DISALLOWED));
}
}
void ToggleCapsLock() {
ImeControllerImpl* ime_controller = Shell::Get()->ime_controller();
ime_controller->SetCapsLockEnabled(!ime_controller->IsCapsLockEnabled());

@ -321,6 +321,9 @@ ASH_EXPORT void ToggleCalendar();
// Turns caps lock on and off.
ASH_EXPORT void ToggleCapsLock();
// Enables or disables camera access in privacy settings.
ASH_EXPORT void ToggleCameraAllowed();
// Toggles the clipboard history.
ASH_EXPORT void ToggleClipboardHistory(bool is_plain_text_paste);

@ -970,6 +970,8 @@ bool AcceleratorControllerImpl::CanPerformAction(
launcher_state_machine_.get());
case AcceleratorAction::kToggleCalendar:
return true;
case AcceleratorAction::kToggleCameraAllowed:
return features::IsToggleCameraShortcutEnabled();
case AcceleratorAction::kToggleCapsLock:
return CanHandleToggleCapsLock(
accelerator, previous_accelerator,
@ -1541,6 +1543,9 @@ void AcceleratorControllerImpl::PerformAction(
base::TimeTicks());
break;
}
case AcceleratorAction::kToggleCameraAllowed:
accelerators::ToggleCameraAllowed();
break;
case AcceleratorAction::kToggleCalendar:
accelerators::ToggleCalendar();
break;

@ -165,6 +165,11 @@ std::vector<ash::AcceleratorData> GetDefaultAccelerators() {
AppendAcceleratorData(accelerators, ash::kGeminiAcceleratorData);
}
if (ash::features::IsToggleCameraShortcutEnabled()) {
AppendAcceleratorData(accelerators,
ash::kToggleCameraAllowedAcceleratorData);
}
return accelerators;
}

@ -2834,6 +2834,15 @@ You can also use the keyboard shortcut. First, highlight text, then press <ph na
<message name="IDS_ASH_DESKS_DESK_16_MINI_VIEW_TITLE" desc="The label of the sixteenth virtual desk thumbnail.">
Desk 16
</message>
<message name="IDS_ASH_CAMERA_NOW_ALLOWED" desc="The toast message that appears when the shortcut to toggle camera access is invoked, and camera access is now enabled.">
Apps can access camera
</message>
<message name="IDS_ASH_CAMERA_NOW_DISALLOWED" desc="The toast message that appears when the shortcut to toggle camera access is invoked, and camera access is now disabled.">
Apps can't access camera
</message>
<message name="IDS_ASH_CAMERA_ACCESS_DISABLED" desc="The toast message that appears when the shortcut to toggle camera access is invoked, but camera access cannot be enabled because there is currently an admin remote desktop session active.">
Can't turn on camera access remotely
</message>
<message name="IDS_ASH_DESKS_MAX_NUM_REACHED" desc="Message shown to users when they attempt to add a new virtual desk when the maximum number of desks has been reached.">
Maximum number of desks reached.
</message>
@ -4251,6 +4260,9 @@ No devices connected.
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_RESIZE_PIP_WINDOW" desc="Label for accelerator action - Resize the picture-in-picture window.">
Switch between the maximum or current size of the picture-in-picture window
</message>
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_CAMERA_ENABLED" desc="Label for accelerator action - Toggle whether the camera access setting is enabled.">
Turn on/off camera access
</message>
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_FOCUS_PREVIOUS_PANE" desc="Label for accelerator action - Move focus to previous pane.">
Move focus to previous pane
</message>

@ -0,0 +1 @@
aedece62ff765a62d22ccb2d49fb357762d6a82d

@ -0,0 +1 @@
2809c83c5a28363acaf2845ca58f7dc2b546e036

@ -0,0 +1 @@
2af96f6c53b44238c80d5fc66e3a264d94976725

@ -0,0 +1 @@
cf8f82a2fdd55359a73604f39bc4081fcdbffc4a

@ -330,7 +330,10 @@ enum class ToastCatalogName {
kCoralSavedGroupLimitMax = 58,
kScannerActionSuccess = 59,
kScannerActionFailure = 60,
kMaxValue = kScannerActionFailure
kCameraNowAllowed = 61,
kCameraNowDisallowed = 62,
kCameraForceDisabled = 63,
kMaxValue = kCameraForceDisabled
};
} // namespace ash

@ -173,6 +173,7 @@ namespace ash {
ACCELERATOR_ACTION_ENTRY(ResizePipWindow) \
ACCELERATOR_ACTION_ENTRY(ToggleGeminiApp) \
ACCELERATOR_ACTION_ENTRY(ToggleDoNotDisturb) \
ACCELERATOR_ACTION_ENTRY(ToggleCameraAllowed) \
/* Debug actions are kept at an offset.*/ \
/* This offset should be kept consistent with the enum*/ \
/* `AcceleratorAction` in*/ \

@ -18,12 +18,12 @@ namespace ash {
namespace {
// The total number of accelerator actions.
constexpr int kAcceleratorActionsTotalNum = 169;
constexpr int kAcceleratorActionsTotalNum = 170;
// The toal number of debug accelerators, these will not be used for hashing.
constexpr int kDebugAcceleratorActionsNum = 28;
// The hash of accelerator actions. Please update this when adding a new
// accelerator action.
constexpr char kAcceleratorActionsHash[] = "c959943640043de5e44136e3154e30d2";
constexpr char kAcceleratorActionsHash[] = "cdcdcd8ea8502dc46c7564f52e56d696";
// Define the mapping between an AcceleratorAction and its string name.
// Example:

@ -456,6 +456,17 @@ ASH_PUBLIC_EXPORT inline constexpr size_t
kToggleDoNotDisturbAcceleratorDataLength =
std::size(kToggleDoNotDisturbAcceleratorData);
// TODO(385364574): Replace this fake temporary keycode with actual keycode.
ASH_PUBLIC_EXPORT inline constexpr AcceleratorData
kToggleCameraAllowedAcceleratorData[] = {
{true, ui::VKEY_F23,
ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
AcceleratorAction::kToggleCameraAllowed},
};
ASH_PUBLIC_EXPORT inline constexpr size_t
kToggleCameraAllowedAcceleratorDataLength =
std::size(kToggleCameraAllowedAcceleratorData);
// The public-facing interface for accelerator handling, which is Ash's duty to
// implement.
class ASH_PUBLIC_EXPORT AcceleratorController {

@ -147,6 +147,7 @@ enum AcceleratorAction {
kResizePipWindow,
kToggleGeminiApp,
kToggleDoNotDisturb,
kToggleCameraAllowed,
// The following are DEBUG actions with an offset. This is to keep the enum
// in sync with `AcceleratorActions` in ash/public/cpp/accelerator_actions.h.
kDebugClearUseKMeansPref = 9000,

@ -297,6 +297,8 @@ EnumTraits<mojom_accelerator_action, ash::AcceleratorAction>::ToMojom(
return mojom_accelerator_action::kToggleGeminiApp;
case ash::kToggleDoNotDisturb:
return mojom_accelerator_action::kToggleDoNotDisturb;
case ash::AcceleratorAction::kToggleCameraAllowed:
return mojom_accelerator_action::kToggleCameraAllowed;
case ash::AcceleratorAction::kDebugClearUseKMeansPref:
return mojom_accelerator_action::kDebugClearUseKMeansPref;
case ash::AcceleratorAction::kDebugKeyboardBacklightToggle:
@ -785,6 +787,9 @@ bool EnumTraits<mojom_accelerator_action, ash::AcceleratorAction>::FromMojom(
case mojom_accelerator_action::kToggleDoNotDisturb:
*out = ash::AcceleratorAction::kToggleDoNotDisturb;
return true;
case mojom_accelerator_action::kToggleCameraAllowed:
*out = ash::AcceleratorAction::kToggleCameraAllowed;
return true;
case mojom_accelerator_action::kDebugClearUseKMeansPref:
*out = ash::AcceleratorAction::kDebugClearUseKMeansPref;
return true;

@ -459,6 +459,8 @@ bool ShouldExcludeItem(const AcceleratorLayoutDetails& details) {
return !features::IsAppLaunchShortcutEnabled();
case kToggleSnapGroupWindowsMinimizeAndRestore:
return true;
case kToggleCameraAllowed:
return !features::IsToggleCameraShortcutEnabled();
}
return false;

@ -571,6 +571,14 @@ const AcceleratorLayoutMap& GetAcceleratorLayoutMap() {
mojom::AcceleratorSubcategory::kGeneralControls, /*locked=*/false,
mojom::AcceleratorLayoutStyle::kDefault,
mojom::AcceleratorSource::kAsh)},
{AcceleratorAction::kToggleCameraAllowed,
AcceleratorLayoutDetails(
AcceleratorAction::kToggleCameraAllowed,
IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_CAMERA_ENABLED,
mojom::AcceleratorCategory::kGeneral,
mojom::AcceleratorSubcategory::kGeneralControls,
/*locked=*/false, mojom::AcceleratorLayoutStyle::kDefault,
mojom::AcceleratorSource::kAsh)},
{AcceleratorAction::kOpenFileManager,
AcceleratorLayoutDetails(
AcceleratorAction::kOpenFileManager,

@ -296,6 +296,7 @@ inline constexpr uint32_t kAcceleratorLayouts[] = {
AcceleratorAction::kSwitchToPreviousUser,
AcceleratorAction::kStartAssistant,
AcceleratorAction::kToggleDoNotDisturb,
AcceleratorAction::kToggleCameraAllowed,
// General > Apps
AcceleratorAction::kOpenFileManager,

@ -2393,6 +2393,9 @@ chromeos/ash/components/peripheral_notification/peripheral_notification_manager.
<int value="58" label="Coral Saved Groups Limit Max"/>
<int value="59" label="Scanner Action Success"/>
<int value="60" label="Scanner Action Failure"/>
<int value="61" label="Apps Can Access Camera"/>
<int value="62" label="Apps Can't Access Camera"/>
<int value="63" label="Can't Turn On Camera Access Remotely"/>
</enum>
<enum name="TogglePickerAction">

@ -152,6 +152,7 @@ chromium-metrics-reviews@google.com.
<variant name="TilingWindowResizeUp"/>
<variant name="ToggleAppList"/>
<variant name="ToggleCalendar"/>
<variant name="ToggleCameraAllowed"/>
<variant name="ToggleCapsLock"/>
<variant name="ToggleClipboardHistory"/>
<variant name="ToggleDictation"/>

@ -191,6 +191,7 @@ chromium-metrics-reviews@google.com.
<int value="137" label="ResizePipWindow"/>
<int value="138" label="ToggleGeminiApp"/>
<int value="139" label="ToggleDoNotDisturb"/>
<int value="140" label="ToggleCameraAllowed"/>
<int value="9000" label="DebugClearUseKMeansPref"/>
<int value="9001" label="DebugKeyboardBacklightToggle"/>
<int value="9002" label="DebugMicrophoneMuteToggle"/>