910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/settings/glic_handler.h"

#include <string>

#include "base/check.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/actor/actor_keyed_service.h"
#include "chrome/browser/actor/actor_keyed_service_factory.h"
#include "chrome/browser/background/glic/glic_launcher_configuration.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/glic/public/glic_enabling.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "chrome/browser/glic/public/glic_keyed_service_factory.h"
#include "chrome/browser/glic/widget/local_hotkey_manager.h"
#include "chrome/browser/user_education/user_education_service.h"
#include "chrome/common/chrome_features.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h"

namespace settings {

GlicHandler::GlicHandler() = default;
GlicHandler::~GlicHandler() = default;

void GlicHandler::RegisterMessages() {
  web_ui()->RegisterMessageCallback(
      "setGlicOsLauncherEnabled",
      base::BindRepeating(&GlicHandler::HandleSetGlicOsLauncherEnabled,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "getGlicShortcut",
      base::BindRepeating(&GlicHandler::HandleGetGlicShortcut,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "setGlicShortcut",
      base::BindRepeating(&GlicHandler::HandleSetGlicShortcut,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "getGlicFocusToggleShortcut",
      base::BindRepeating(&GlicHandler::HandleGetGlicFocusToggleShortcut,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "setGlicFocusToggleShortcut",
      base::BindRepeating(&GlicHandler::HandleSetGlicFocusToggleShortcut,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "setShortcutSuspensionState",
      base::BindRepeating(&GlicHandler::HandleSetShortcutSuspensionState,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "getGlicDisallowedByAdmin",
      base::BindRepeating(&GlicHandler::HandleGetGlicDisallowedByAdmin,
                          base::Unretained(this)));
}

void GlicHandler::OnJavascriptAllowed() {
  Profile* profile = Profile::FromWebUI(web_ui());
  if (auto* service =
          glic::GlicKeyedServiceFactory::GetGlicKeyedService(profile)) {
    // Unretained is safe here since our subscription will expire upon our
    // destruction.
    glic_enabling_subscription_ =
        std::make_unique<base::CallbackListSubscription>(
            service->enabling().RegisterAllowedChanged(base::BindRepeating(
                &GlicHandler::FireOnGlicDisallowedByAdminChanged,
                base::Unretained(this))));
  }

  if (auto* actor_service =
          actor::ActorKeyedServiceFactory::GetActorKeyedService(profile)) {
    web_actuation_subscription_ =
        actor_service->AddActOnWebCapabilityChangedCallback(
            base::BindRepeating(&GlicHandler::OnWebActuationCapabilityChanged,
                                base::Unretained(this)));
  }
}

void GlicHandler::OnJavascriptDisallowed() {
  glic_enabling_subscription_.reset();
  web_actuation_subscription_ = {};
}

void GlicHandler::SetWebUIForTesting(content::WebUI* web_ui) {
  set_web_ui(web_ui);
}

void GlicHandler::HandleSetGlicOsLauncherEnabled(
    const base::Value::List& args) {
  UserEducationService::MaybeNotifyNewBadgeFeatureUsed(
      web_ui()->GetWebContents()->GetBrowserContext(), features::kGlic);
}

void GlicHandler::HandleGetGlicShortcut(const base::Value::List& args) {
  CHECK_EQ(1U, args.size());
  const base::Value& callback_id = args[0];

  AllowJavascript();
  ResolveJavascriptCallback(
      callback_id,
      base::UTF16ToUTF8(glic::GlicLauncherConfiguration::GetGlobalHotkey()
                            .GetShortcutText()));
}

void GlicHandler::HandleSetGlicShortcut(const base::Value::List& args) {
  CHECK_EQ(2U, args.size());
  const base::Value& callback_id = args[0];
  const std::string accelerator_string = args[1].GetString();
  g_browser_process->local_state()->SetString(glic::prefs::kGlicLauncherHotkey,
                                              accelerator_string);

  UserEducationService::MaybeNotifyNewBadgeFeatureUsed(
      web_ui()->GetWebContents()->GetBrowserContext(),
      features::kGlicKeyboardShortcutNewBadge);

  AllowJavascript();
  ResolveJavascriptCallback(callback_id, base::Value());
}

void GlicHandler::HandleGetGlicFocusToggleShortcut(
    const base::Value::List& args) {
  CHECK_EQ(1U, args.size());
  const base::Value& callback_id = args[0];

  AllowJavascript();
  ResolveJavascriptCallback(
      callback_id,
      base::UTF16ToUTF8(glic::LocalHotkeyManager::GetConfigurableAccelerator(
                            glic::LocalHotkeyManager::Hotkey::kFocusToggle)
                            .GetShortcutText()));
}

void GlicHandler::HandleSetGlicFocusToggleShortcut(
    const base::Value::List& args) {
  CHECK_EQ(2U, args.size());
  const base::Value& callback_id = args[0];
  const std::string accelerator_string = args[1].GetString();
  g_browser_process->local_state()->SetString(
      glic::prefs::kGlicFocusToggleHotkey, accelerator_string);

  AllowJavascript();
  ResolveJavascriptCallback(callback_id, base::Value());
}

void GlicHandler::HandleSetShortcutSuspensionState(
    const base::Value::List& args) {
  CHECK_EQ(1U, args.size());
  const bool should_suspend = args[0].GetBool();
  auto* const global_accelerator_listener =
      ui::GlobalAcceleratorListener::GetInstance();
  // `global_accelerator_listener` may be null on Linux Wayland builds.
  if (global_accelerator_listener) {
    global_accelerator_listener->SetShortcutHandlingSuspended(should_suspend);
  }
}

void GlicHandler::HandleGetGlicDisallowedByAdmin(
    const base::Value::List& args) {
  CHECK_EQ(1U, args.size());
  const base::Value& callback_id = args[0];
  AllowJavascript();

  Profile* profile = Profile::FromWebUI(web_ui());
  const bool disallowed =
      glic::GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin();

  ResolveJavascriptCallback(callback_id, base::Value(disallowed));
}

void GlicHandler::FireOnGlicDisallowedByAdminChanged() {
  Profile* profile = Profile::FromWebUI(web_ui());
  const bool disallowed =
      glic::GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin();
  FireWebUIListener("glic-disallowed-by-admin-changed",
                    base::Value(disallowed));
}

void GlicHandler::OnWebActuationCapabilityChanged(bool can_act_on_web) {
  FireWebUIListener("glic-web-actuation-capability-changed",
                    base::Value(can_act_on_web));
}

}  // namespace settings