boca: Set up SWA skeleton

BUG=b:336881992
TEST=Manually verify SWA setup.
Design sketch: go/bocaclient

Change-Id: Ie48c627599b8bd95c6f3b0b56701505fad5d5a1b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5531858
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Jason Zhang <jiajunz@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: April Zhou <aprilzhou@google.com>
Cr-Commit-Position: refs/heads/main@{#1301460}
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 640e0b0..11a1e22 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -440,6 +440,9 @@
              "CheckPasswordsAgainstCryptohomeHelper",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables or disables Boca feature on ChromeOS
+BASE_FEATURE(kBoca, "Boca", base::FEATURE_DISABLED_BY_DEFAULT);
+
 // When enabled alongside the keyboard auto-repeat setting, holding down Ctrl+V
 // will cause the clipboard history menu to show. From there, the user can
 // select a clipboard history item to replace the initially pasted content.
@@ -1190,9 +1193,6 @@
              "FloatingWorkspace",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables or disables Floating Workspace feature on ChromeOS
-BASE_FEATURE(kClassHub, "ClassHub", base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Enables chrome.fileSystemProvider file systems in Files app Recents view.
 BASE_FEATURE(kFSPsInRecents, "FSPsInRecents", base::FEATURE_ENABLED_BY_DEFAULT);
 
@@ -3333,6 +3333,10 @@
   return base::FeatureList::IsEnabled(kCheckPasswordsAgainstCryptohomeHelper);
 }
 
+bool IsBocaEnabled() {
+  return base::FeatureList::IsEnabled(kBoca);
+}
+
 bool IsClipboardHistoryLongpressEnabled() {
   return base::FeatureList::IsEnabled(kClipboardHistoryLongpress);
 }
@@ -3578,10 +3582,6 @@
   return base::FeatureList::IsEnabled(kFloatingWorkspaceV2);
 }
 
-bool IsClassHubEnabled() {
-  return base::FeatureList::IsEnabled(kClassHub);
-}
-
 bool IsFocusModeEnabled() {
   return base::FeatureList::IsEnabled(kFocusMode);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 2e34211c9..1f51828 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -130,6 +130,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCellularUseSecondEuicc);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kCheckPasswordsAgainstCryptohomeHelper);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBoca);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kClipboardHistoryLongpress);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -368,7 +369,6 @@
 BASE_DECLARE_FEATURE(kFirstPartyVietnameseInput);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFlexAutoEnrollment);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFloatingWorkspace);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kClassHub);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::FeatureParam<base::TimeDelta>
     kFloatingWorkspaceMaxTimeAvailableForRestoreAfterLogin;
@@ -1055,7 +1055,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFlexAutoEnrollmentEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFloatingWorkspaceEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFloatingWorkspaceV2Enabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool isClassHubEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBocaEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFocusModeEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool ShouldForceEnableServerSideSpeechRecognitionForDev();
diff --git a/ash/webui/boca_ui/BUILD.gn b/ash/webui/boca_ui/BUILD.gn
new file mode 100644
index 0000000..7bd2055
--- /dev/null
+++ b/ash/webui/boca_ui/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD - style license that can be
+# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
+import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/preprocess_if_expr.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+assert(is_chromeos_ash, "Coba App is ash-chrome only")
+
+static_library("boca_ui") {
+  sources = [
+    "boca_ui.cc",
+    "boca_ui.h",
+    "url_constants.h",
+  ]
+  deps = [
+    "resources:resources",
+    "//ash/constants:constants",
+    "//ash/webui/common:chrome_os_webui_config",
+    "//ash/webui/system_apps/public:system_web_app_config",
+    "//content/public/browser",
+    "//ui/webui",
+  ]
+}
diff --git a/ash/webui/boca_ui/OWNERS b/ash/webui/boca_ui/OWNERS
new file mode 100644
index 0000000..b87ddfc
--- /dev/null
+++ b/ash/webui/boca_ui/OWNERS
@@ -0,0 +1,3 @@
+aprilzhou@google.com
+bzielinski@google.com
+vshenvi@google.com
diff --git a/ash/webui/boca_ui/boca_ui.cc b/ash/webui/boca_ui/boca_ui.cc
new file mode 100644
index 0000000..59da48b
--- /dev/null
+++ b/ash/webui/boca_ui/boca_ui.cc
@@ -0,0 +1,40 @@
+// Copyright 2024 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/webui/boca_ui/boca_ui.h"
+
+#include "ash/constants/ash_features.h"
+#include "ash/webui/boca_ui/url_constants.h"
+#include "ash/webui/common/chrome_os_webui_config.h"
+#include "ash/webui/grit/ash_boca_ui_resources.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+namespace ash {
+
+bool BocaUIConfig::IsWebUIEnabled(content::BrowserContext* browser_context) {
+  return ash::features::IsBocaEnabled();
+}
+
+BocaUI::BocaUI(content::WebUI* web_ui) : ui::MojoWebUIController(web_ui) {
+  auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
+  auto* html_source = content::WebUIDataSource::CreateAndAdd(
+      browser_context, ash::kChromeBocaAppHost);
+
+  html_source->AddResourcePath("index.html", IDR_ASH_BOCA_UI_INDEX_HTML);
+#if !DCHECK_IS_ON()
+  // If a user goes to an invalid url and non-DCHECK mode (DHECK = debug mode)
+  // is set, serve a default page so the user sees your default page instead
+  // of an unexpected error. But if DCHECK is set, the user will be a
+  // developer and be able to identify an error occurred.
+  html_source->SetDefaultResource(IDR_ASH_BOCA_UI_INDEX_HTML);
+#endif  // !DCHECK_IS_ON()
+}
+
+BocaUI::~BocaUI() = default;
+
+WEB_UI_CONTROLLER_TYPE_IMPL(BocaUI)
+}  // namespace ash
diff --git a/ash/webui/boca_ui/boca_ui.h b/ash/webui/boca_ui/boca_ui.h
new file mode 100644
index 0000000..39d41be
--- /dev/null
+++ b/ash/webui/boca_ui/boca_ui.h
@@ -0,0 +1,39 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WEBUI_BOCA_UI_BOCA_UI_H_
+#define ASH_WEBUI_BOCA_UI_BOCA_UI_H_
+
+#include "ash/webui/boca_ui/url_constants.h"
+#include "ash/webui/common/chrome_os_webui_config.h"
+#include "ash/webui/system_apps/public/system_web_app_ui_config.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+#include "ui/webui/untrusted_web_ui_controller.h"
+
+namespace ash {
+class BocaUI;
+
+// WebUI config for Boca SWA.
+class BocaUIConfig : public SystemWebAppUIConfig<BocaUI> {
+ public:
+  BocaUIConfig()
+      : SystemWebAppUIConfig(kChromeBocaAppHost, SystemWebAppType::BOCA) {}
+  bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
+};
+
+// The WebUI for chrome://boca-app/.
+class BocaUI : public ui::MojoWebUIController {
+ public:
+  explicit BocaUI(content::WebUI* web_ui);
+  BocaUI(const BocaUI&) = delete;
+  BocaUI& operator=(const BocaUI&) = delete;
+  ~BocaUI() override;
+
+ private:
+  WEB_UI_CONTROLLER_TYPE_DECL();
+};
+
+}  // namespace ash
+
+#endif  // ASH_WEBUI_BOCA_UI_BOCA_UI_H_
diff --git a/ash/webui/boca_ui/resources/BUILD.gn b/ash/webui/boca_ui/resources/BUILD.gn
new file mode 100644
index 0000000..9b6e7b08
--- /dev/null
+++ b/ash/webui/boca_ui/resources/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD - style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+import("//ui/webui/resources/tools/build_webui.gni")
+
+assert(is_chromeos_ash)
+
+build_webui("build") {
+  grd_prefix = "ash_boca_ui"
+  static_files = [
+    "index.html",
+    "app_icon_120.png",
+  ]
+
+  # Files not holding a CustomElement element definition, or the CustomElement
+  # does not have a corresponding HTML template.
+  non_web_component_files = [ "index.ts" ]
+
+  ts_composite = true
+
+  grit_output_dir = "$root_gen_dir/ash/webui"
+}
diff --git a/ash/webui/boca_ui/resources/app_icon_120.png b/ash/webui/boca_ui/resources/app_icon_120.png
new file mode 100644
index 0000000..360c165
--- /dev/null
+++ b/ash/webui/boca_ui/resources/app_icon_120.png
Binary files differ
diff --git a/ash/webui/boca_ui/resources/index.html b/ash/webui/boca_ui/resources/index.html
new file mode 100644
index 0000000..1ee1251
--- /dev/null
+++ b/ash/webui/boca_ui/resources/index.html
@@ -0,0 +1,9 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<title>BocaUI</title>
+<h1 id="header">BocaUI</h1>
+</html>
diff --git a/ash/webui/boca_ui/resources/index.ts b/ash/webui/boca_ui/resources/index.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ash/webui/boca_ui/resources/index.ts
diff --git a/ash/webui/boca_ui/url_constants.h b/ash/webui/boca_ui/url_constants.h
new file mode 100644
index 0000000..51bf66b
--- /dev/null
+++ b/ash/webui/boca_ui/url_constants.h
@@ -0,0 +1,17 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WEBUI_BOCA_UI_URL_CONSTANTS_H_
+#define ASH_WEBUI_BOCA_UI_URL_CONSTANTS_H_
+
+namespace ash {
+// Boca App Host.
+inline constexpr char kChromeBocaAppHost[] = "boca-app";
+// Boca App URL.
+inline constexpr char kChromeBocaAppURL[] = "chrome://boca-app/";
+// Boca App Index URL.
+inline constexpr char kChromeBocaAppIndexURL[] = "chrome://boca-app/index.html";
+}  // namespace ash
+
+#endif  // ASH_WEBUI_BOCA_UI_URL_CONSTANTS_H_
diff --git a/ash/webui/system_apps/public/system_web_app_type.h b/ash/webui/system_apps/public/system_web_app_type.h
index ee873060..42fe7ae 100644
--- a/ash/webui/system_apps/public/system_web_app_type.h
+++ b/ash/webui/system_apps/public/system_web_app_type.h
@@ -121,6 +121,11 @@
   // Contact: cros-peripherals@google.com
   PRINT_PREVIEW_CROS = 26,
 
+  // Boca implementation.
+  // Source: //ash/webui/boca_ui/
+  // Contact: cros-edu-eng@google.com
+  BOCA = 27,
+
   // When adding a new System App, remember to:
   //
   // 1. Add a corresponding histogram suffix in WebAppSystemAppInternalName
@@ -160,7 +165,7 @@
   //
   // 8. Have one of System Web App Platform owners review the CL.
   //    See: //ash/webui/PLATFORM_OWNERS
-  kMaxValue = PRINT_PREVIEW_CROS,
+  kMaxValue = BOCA,
 };
 
 }  // namespace ash
diff --git a/chrome/browser/apps/app_service/policy_util.cc b/chrome/browser/apps/app_service/policy_util.cc
index 624ce98..e4de3c9 100644
--- a/chrome/browser/apps/app_service/policy_util.cc
+++ b/chrome/browser/apps/app_service/policy_util.cc
@@ -64,7 +64,8 @@
          {"firmware_update", ash::SystemWebAppType::FIRMWARE_UPDATE},
          {"os_flags", ash::SystemWebAppType::OS_FLAGS},
          {"vc_background", ash::SystemWebAppType::VC_BACKGROUND},
-         {"print_preview_cros", ash::SystemWebAppType::PRINT_PREVIEW_CROS}});
+         {"print_preview_cros", ash::SystemWebAppType::PRINT_PREVIEW_CROS},
+         {"boca", ash::SystemWebAppType::BOCA}});
 
 constexpr ash::SystemWebAppType GetMaxSystemWebAppType() {
   return base::ranges::max(kSystemWebAppsMapping, base::ranges::less{},
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 71ac3aa3..ebb8aba 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -3436,6 +3436,8 @@
     "system_logs/virtual_keyboard_log_source.h",
     "system_token_cert_db_initializer.cc",
     "system_token_cert_db_initializer.h",
+    "system_web_apps/apps/boca_web_app_info.cc",
+    "system_web_apps/apps/boca_web_app_info.h",
     "system_web_apps/apps/calculator_app/calculator_app_utils.cc",
     "system_web_apps/apps/calculator_app/calculator_app_utils.h",
     "system_web_apps/apps/camera_app/camera_app_survey_handler.cc",
@@ -3733,6 +3735,7 @@
     "//ash/public/mojom:accelerator_info",
     "//ash/public/mojom:hid_preserving_bluetooth_state_controller",
     "//ash/quick_pair/common",
+    "//ash/webui/boca_ui",
     "//ash/webui/camera_app_ui",
     "//ash/webui/common/mojom:sea_pen",
     "//ash/webui/connectivity_diagnostics",
@@ -4141,6 +4144,7 @@
     "//ash/resources/vector_icons",
     "//ash/strings",
     "//ash/style",
+    "//ash/webui/boca_ui/resources",
     "//ash/webui/camera_app_ui:document_scanning",
     "//ash/webui/camera_app_ui:ocr",
     "//ash/webui/camera_app_ui/resources/strings",
diff --git a/chrome/browser/ash/system_web_apps/apps/BUILD.gn b/chrome/browser/ash/system_web_apps/apps/BUILD.gn
index 3ef0d20..9e88153 100644
--- a/chrome/browser/ash/system_web_apps/apps/BUILD.gn
+++ b/chrome/browser/ash/system_web_apps/apps/BUILD.gn
@@ -39,6 +39,7 @@
   }
 
   deps = [
+    "//ash/webui/boca_ui",
     "//ash/webui/demo_mode_app_ui",
     "//ash/webui/diagnostics_ui",
     "//ash/webui/firmware_update_ui",
diff --git a/chrome/browser/ash/system_web_apps/apps/boca_web_app_info.cc b/chrome/browser/ash/system_web_apps/apps/boca_web_app_info.cc
new file mode 100644
index 0000000..2fa4845b
--- /dev/null
+++ b/chrome/browser/ash/system_web_apps/apps/boca_web_app_info.cc
@@ -0,0 +1,53 @@
+// Copyright 2024 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/ash/system_web_apps/apps/boca_web_app_info.h"
+
+#include "ash/constants/ash_features.h"
+#include "ash/webui/boca_ui/url_constants.h"
+#include "ash/webui/grit/ash_boca_ui_resources.h"
+#include "chrome/browser/ash/system_web_apps/apps/system_web_app_install_utils.h"
+#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
+#include "chrome/browser/web_applications/web_app_install_info.h"
+#include "chromeos/constants/chromeos_features.h"
+
+std::unique_ptr<web_app::WebAppInstallInfo> CreateWebAppInfoForBocaApp() {
+  std::unique_ptr<web_app::WebAppInstallInfo> info =
+      std::make_unique<web_app::WebAppInstallInfo>();
+  info->start_url = GURL(ash::kChromeBocaAppIndexURL);
+  info->scope = GURL(ash::kChromeBocaAppIndexURL);
+  // TODO(aprilzhou): Convert the title to a localized string
+  info->title = u"BOCA";
+  web_app::CreateIconInfoForSystemWebApp(
+      info->start_url,
+      {{"app_icon_120.png", 120, IDR_ASH_BOCA_UI_APP_ICON_120_PNG}}, *info);
+  info->theme_color =
+      web_app::GetDefaultBackgroundColor(/*use_dark_mode=*/false);
+  info->dark_mode_theme_color =
+      web_app::GetDefaultBackgroundColor(/*use_dark_mode=*/true);
+  info->background_color = info->theme_color;
+  info->display_mode = blink::mojom::DisplayMode::kStandalone;
+  info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone;
+
+  return info;
+}
+
+BocaSystemAppDelegate::BocaSystemAppDelegate(Profile* profile)
+    : ash::SystemWebAppDelegate(ash::SystemWebAppType::BOCA,
+                                "Boca",
+                                GURL(ash::kChromeBocaAppURL),
+                                profile) {}
+
+std::unique_ptr<web_app::WebAppInstallInfo>
+BocaSystemAppDelegate::GetWebAppInfo() const {
+  return CreateWebAppInfoForBocaApp();
+}
+
+bool BocaSystemAppDelegate::ShouldCaptureNavigations() const {
+  return true;
+}
+
+bool BocaSystemAppDelegate::IsAppEnabled() const {
+  return ash::features::IsBocaEnabled();
+}
diff --git a/chrome/browser/ash/system_web_apps/apps/boca_web_app_info.h b/chrome/browser/ash/system_web_apps/apps/boca_web_app_info.h
new file mode 100644
index 0000000..128bd11
--- /dev/null
+++ b/chrome/browser/ash/system_web_apps/apps/boca_web_app_info.h
@@ -0,0 +1,27 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_BOCA_WEB_APP_INFO_H_
+#define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_BOCA_WEB_APP_INFO_H_
+
+#include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h"
+
+namespace web_app {
+struct WebAppInstallInfo;
+}  // namespace web_app
+
+// For Boca SWA.
+class BocaSystemAppDelegate : public ash::SystemWebAppDelegate {
+ public:
+  explicit BocaSystemAppDelegate(Profile* profile);
+
+  // ash::SystemWebAppDelegate overrides:
+  std::unique_ptr<web_app::WebAppInstallInfo> GetWebAppInfo() const override;
+  bool ShouldCaptureNavigations() const override;
+  bool IsAppEnabled() const override;
+};
+
+std::unique_ptr<web_app::WebAppInstallInfo> CreateWebAppInfoForBocaApp();
+
+#endif  // CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_BOCA_WEB_APP_INFO_H_
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
index 907dd2c..bb852c4 100644
--- a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
+++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
@@ -39,6 +39,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/version.h"
+#include "chrome/browser/ash/system_web_apps/apps/boca_web_app_info.h"
 #include "chrome/browser/ash/system_web_apps/apps/camera_app/camera_system_web_app_info.h"
 #include "chrome/browser/ash/system_web_apps/apps/connectivity_diagnostics_system_web_app_info.h"
 #include "chrome/browser/ash/system_web_apps/apps/crosh_system_web_app_info.h"
@@ -141,6 +142,9 @@
       std::make_unique<vc_background_ui::VcBackgroundUISystemAppDelegate>(
           profile));
   info_vec.push_back(std::make_unique<PrintPreviewCrosDelegate>(profile));
+  if (features::IsBocaEnabled()) {
+    info_vec.push_back(std::make_unique<BocaSystemAppDelegate>(profile));
+  }
 
 #if !defined(OFFICIAL_BUILD)
   info_vec.push_back(std::make_unique<SampleSystemAppDelegate>(profile));
diff --git a/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto b/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto
index e233d6f..a0759a7 100644
--- a/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto
+++ b/chrome/browser/ash/system_web_apps/types/proto/system_web_app_data.proto
@@ -37,6 +37,7 @@
     FACE_ML = 24;
     VC_BACKGROUND = 25;
     PRINT_PREVIEW_CROS = 26;
+    BOCA = 27;
   };
 
   optional SystemWebAppType system_app_type = 1;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 5fa8e0e..6ce36603 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3781,6 +3781,7 @@
       "//ash/quick_pair/repository",
       "//ash/quick_pair/ui",
       "//ash/style:style",
+      "//ash/webui/boca_ui",
       "//ash/webui/camera_app_ui",
       "//ash/webui/color_internals",
       "//ash/webui/common:chrome_os_webui_config",
diff --git a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
index c0edaedd..d66ab17 100644
--- a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
+++ b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/app_mode/app_mode_utils.h"         // nogncheck
 #include "chrome/browser/feedback/feedback_dialog_utils.h"  // nogncheck
 
+#include "ash/webui/boca_ui/boca_ui.h"
 #include "ash/webui/camera_app_ui/camera_app_ui.h"
 #include "ash/webui/color_internals/color_internals_ui.h"
 #include "ash/webui/connectivity_diagnostics/connectivity_diagnostics_ui.h"
@@ -221,6 +222,7 @@
   map.AddWebUIConfig(std::make_unique<AssistantOptInUIConfig>());
   map.AddWebUIConfig(std::make_unique<AudioUIConfig>());
   map.AddWebUIConfig(std::make_unique<BluetoothPairingDialogUIConfig>());
+  map.AddWebUIConfig(std::make_unique<BocaUIConfig>());
   map.AddWebUIConfig(std::make_unique<BorealisInstallerUIConfig>());
   map.AddWebUIConfig(std::make_unique<CertificateManagerDialogUIConfig>());
   map.AddWebUIConfig(std::make_unique<cloud_upload::CloudUploadUIConfig>());
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 87e4b16..81bbfbf 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -234,6 +234,7 @@
         "$root_gen_dir/ash/public/cpp/resources/ash_public_unscaled_resources.pak",
         "$root_gen_dir/ash/system/mahi/resources/mahi_resources.pak",
         "$root_gen_dir/ash/system/video_conference/resources/vc_resources.pak",
+        "$root_gen_dir/ash/webui/ash_boca_ui_resources.pak",
         "$root_gen_dir/ash/webui/ash_camera_app_resources.pak",
         "$root_gen_dir/ash/webui/ash_color_internals_resources.pak",
         "$root_gen_dir/ash/webui/ash_demo_mode_app_resources.pak",
@@ -318,6 +319,7 @@
         "//ash/public/cpp/resources:ash_public_unscaled_resources",
         "//ash/system/mahi/resources:mahi_resources",
         "//ash/system/video_conference/resources:vc_resources",
+        "//ash/webui/boca_ui/resources:resources",
         "//ash/webui/color_internals/resources:resources",
         "//ash/webui/common/resources:resources",
         "//ash/webui/common/resources/office_fallback:resources",
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index f3ca54d7..ff0b789 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -777,6 +777,10 @@
   "chromeos/ash/resources/internal/ash_internal_strings.grd": {
     "messages": [5780],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/ash/webui/boca_ui/resources/resources.grd": {
+    "META": {"sizes": {"includes": [50],}},
+    "includes": [5790],
+  },
   "<(SHARED_INTERMEDIATE_DIR)/ash/webui/camera_app_ui/ash_camera_app_resources.grd": {
     "META": {"sizes": {"includes": [300],}},
     "includes": [5800],
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index f615670a..471b94b9d89 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -4541,6 +4541,7 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="WebAppSystemAppInternalName" separator=".">
+  <suffix name="Boca" label="Boca"/>
   <suffix name="Camera" label="Camera"/>
   <suffix name="ConnectivityDiagnostics" label="Connectivity Diagnostics"/>
   <suffix name="Crosh" label="Crosh"/>