chromium/ash/system/input_device_settings/input_device_settings_policy_handler.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/system/input_device_settings/input_device_settings_policy_handler.h"

#include "ash/constants/ash_pref_names.h"
#include "ash/public/mojom/input_device_settings.mojom.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"

namespace ash {
namespace {

mojom::InputDeviceSettingsPolicyPtr GetBooleanPreferencePolicy(
    const PrefService* pref_service,
    const std::string& pref_name) {
  mojom::InputDeviceSettingsPolicyPtr policy;

  CHECK(pref_service);
  const auto* pref = pref_service->FindPreference(pref_name);
  if (!pref) {
    return policy;
  }

  if (pref->IsManaged()) {
    auto* value = pref->GetValue();
    CHECK(value && value->is_bool());
    policy = mojom::InputDeviceSettingsPolicy::New(
        mojom::PolicyStatus::kManaged, value->GetBool());

    // Prefs with recommended values must use `GetRecommendedValue` instead
    // of `IsRecommended` as `IsRecommended` may return false even if the pref
    // has a recommended value.
  } else if (auto* value = pref->GetRecommendedValue(); value) {
    CHECK(value->is_bool());
    policy = mojom::InputDeviceSettingsPolicy::New(
        mojom::PolicyStatus::kRecommended, value->GetBool());
  }

  return policy;
}

mojom::InputDeviceSettingsFkeyPolicyPtr GetFkeyPreferencePolicy(
    const PrefService* pref_service,
    const std::string& pref_name) {
  mojom::InputDeviceSettingsFkeyPolicyPtr policy;

  const auto* pref = pref_service->FindPreference(pref_name);
  if (!pref) {
    return policy;
  }

  if (pref->IsManaged()) {
    auto* value = pref->GetValue();
    CHECK(value && value->is_int());
    policy = mojom::InputDeviceSettingsFkeyPolicy::New(
        mojom::PolicyStatus::kManaged,
        static_cast<ui::mojom::ExtendedFkeysModifier>(value->GetInt()));

    // Prefs with recommended values must use `GetRecommendedValue` instead
    // of `IsRecommended` as `IsRecommended` may return false even if the pref
    // has a recommended value.
  } else if (auto* value = pref->GetRecommendedValue(); value) {
    CHECK(value->is_int());
    policy = mojom::InputDeviceSettingsFkeyPolicy::New(
        mojom::PolicyStatus::kRecommended,
        static_cast<ui::mojom::ExtendedFkeysModifier>(value->GetInt()));
  }

  return policy;
}

mojom::InputDeviceSettingsSixPackKeyPolicyPtr GetSixPackKeyPreferencePolicy(
    const PrefService* pref_service,
    const std::string& pref_name) {
  mojom::InputDeviceSettingsSixPackKeyPolicyPtr policy;

  const auto* pref = pref_service->FindPreference(pref_name);
  if (!pref) {
    return policy;
  }

  if (pref->IsManaged()) {
    auto* value = pref->GetValue();
    CHECK(value && value->is_int());
    if (pref_name == prefs::kInsertKeyModifier) {
      CHECK(static_cast<ui::mojom::SixPackShortcutModifier>(value->GetInt()) !=
            ui::mojom::SixPackShortcutModifier::kAlt);
    }
    policy = mojom::InputDeviceSettingsSixPackKeyPolicy::New(
        mojom::PolicyStatus::kManaged,
        static_cast<ui::mojom::SixPackShortcutModifier>(value->GetInt()));

    // Prefs with recommended values must use `GetRecommendedValue` instead
    // of `IsRecommended` as `IsRecommended` may return false even if the pref
    // has a recommended value.
  } else if (auto* value = pref->GetRecommendedValue(); value) {
    CHECK(value->is_int());
    if (pref_name == prefs::kInsertKeyModifier) {
      CHECK(static_cast<ui::mojom::SixPackShortcutModifier>(value->GetInt()) !=
            ui::mojom::SixPackShortcutModifier::kAlt);
    }
    policy = mojom::InputDeviceSettingsSixPackKeyPolicy::New(
        mojom::PolicyStatus::kRecommended,
        static_cast<ui::mojom::SixPackShortcutModifier>(value->GetInt()));
  }

  return policy;
}

}  // namespace

InputDeviceSettingsPolicyHandler::InputDeviceSettingsPolicyHandler(
    EnterprisePolicyCallback keyboard_policy_callback,
    EnterprisePolicyCallback mouse_policy_callback)
    : keyboard_policy_callback_(std::move(keyboard_policy_callback)),
      mouse_policy_callback_(std::move(mouse_policy_callback)) {}
InputDeviceSettingsPolicyHandler::~InputDeviceSettingsPolicyHandler() = default;

void InputDeviceSettingsPolicyHandler::Initialize(PrefService* local_state,
                                                  PrefService* pref_service) {
  has_user_prefs_ = pref_service != nullptr;
  if (local_state) {
    pref_change_registrar_local_state_.Init(local_state);
    // Add pref observer for kOwnerPrimaryMouseButtonRight only when there is
    // no user pref_service.
    if (!pref_service) {
      pref_change_registrar_local_state_.Add(
          prefs::kOwnerPrimaryMouseButtonRight,
          base::BindRepeating(
              &InputDeviceSettingsPolicyHandler::OnMousePoliciesChanged,
              base::Unretained(this)));
    }
    pref_change_registrar_local_state_.Add(
        prefs::kDeviceSwitchFunctionKeysBehaviorEnabled,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
  }
  if (pref_service) {
    pref_change_registrar_.Init(pref_service);
    pref_change_registrar_.Add(
        prefs::kPrimaryMouseButtonRight,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnMousePoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kSendFunctionKeys,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kF11KeyModifier,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kF12KeyModifier,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kHomeAndEndKeysModifier,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kPageUpAndPageDownKeysModifier,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kDeleteKeyModifier,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
    pref_change_registrar_.Add(
        prefs::kInsertKeyModifier,
        base::BindRepeating(
            &InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged,
            base::Unretained(this)));
  }

  RefreshKeyboardPolicies(/*notify=*/false);
  RefreshMousePolicies(/*notify=*/false);
}

void InputDeviceSettingsPolicyHandler::RefreshKeyboardPolicies(bool notify) {
  if (has_user_prefs_) {
    keyboard_policies_.top_row_are_fkeys_policy = GetBooleanPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kSendFunctionKeys);
    keyboard_policies_.f11_key_policy = GetFkeyPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kF11KeyModifier);
    keyboard_policies_.f12_key_policy = GetFkeyPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kF12KeyModifier);
    keyboard_policies_.home_and_end_keys_policy = GetSixPackKeyPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kHomeAndEndKeysModifier);
    keyboard_policies_.page_up_and_page_down_keys_policy =
        GetSixPackKeyPreferencePolicy(pref_change_registrar_.prefs(),
                                      prefs::kPageUpAndPageDownKeysModifier);
    keyboard_policies_.delete_key_policy = GetSixPackKeyPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kDeleteKeyModifier);
    keyboard_policies_.insert_key_policy = GetSixPackKeyPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kInsertKeyModifier);
  }

  if (pref_change_registrar_local_state_.prefs()) {
    keyboard_policies_.enable_meta_fkey_rewrites_policy =
        GetBooleanPreferencePolicy(
            pref_change_registrar_local_state_.prefs(),
            prefs::kDeviceSwitchFunctionKeysBehaviorEnabled);
  }

  if (notify) {
    keyboard_policy_callback_.Run();
  }
}

void InputDeviceSettingsPolicyHandler::RefreshMousePolicies(bool notify) {
  if (has_user_prefs_) {
    mouse_policies_.swap_right_policy = GetBooleanPreferencePolicy(
        pref_change_registrar_.prefs(), prefs::kPrimaryMouseButtonRight);
  } else {
    mouse_policies_.swap_right_policy =
        GetBooleanPreferencePolicy(pref_change_registrar_local_state_.prefs(),
                                   prefs::kOwnerPrimaryMouseButtonRight);
  }

  if (notify) {
    mouse_policy_callback_.Run();
  }
}

void InputDeviceSettingsPolicyHandler::OnKeyboardPoliciesChanged(
    const std::string& pref_name) {
  RefreshKeyboardPolicies(/*notify=*/true);
}

void InputDeviceSettingsPolicyHandler::OnMousePoliciesChanged(
    const std::string& pref_name) {
  RefreshMousePolicies(/*notify=*/true);
}

}  // namespace ash