// Copyright 2012 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/ash/shell_delegate/chrome_shell_delegate.h"

#include <memory>
#include <optional>
#include <string>
#include <utility>

#include "ash/accelerators/accelerator_prefs_delegate.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "ash/game_dashboard/game_dashboard_delegate.h"
#include "ash/public/cpp/app_types_util.h"
#include "ash/public/cpp/new_window_delegate.h"
#include "ash/public/cpp/tab_strip_delegate.h"
#include "ash/shell_delegate.h"
#include "ash/webui/settings/public/constants/routes.mojom.h"
#include "ash/webui/settings/public/constants/setting.mojom-shared.h"
#include "ash/wm/window_pin_util.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_state.h"
#include "base/check.h"
#include "base/check_deref.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "cc/input/touch_action.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/ash/api/tasks/chrome_tasks_delegate.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/arc/locked_fullscreen/arc_locked_fullscreen_manager.h"
#include "chrome/browser/ash/arc/session/arc_service_launcher.h"
#include "chrome/browser/ash/browser_delegate/browser_controller.h"
#include "chrome/browser/ash/browser_delegate/browser_delegate.h"
#include "chrome/browser/ash/file_manager/path_util.h"
#include "chrome/browser/ash/multidevice_setup/multidevice_setup_service_factory.h"
#include "chrome/browser/ash/scanner/chrome_scanner_delegate.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part_ash.h"
#include "chrome/browser/feedback/feedback_uploader_chrome.h"
#include "chrome/browser/feedback/feedback_uploader_factory_chrome.h"
#include "chrome/browser/global_features.h"
#include "chrome/browser/nearby_sharing/nearby_share_delegate_impl.h"
#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h"
#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/ui/ash/accelerator/chrome_accelerator_prefs_delegate.h"
#include "chrome/browser/ui/ash/accessibility/chrome_accessibility_delegate.h"
#include "chrome/browser/ui/ash/back_gesture/back_gesture_contextual_nudge_delegate.h"
#include "chrome/browser/ui/ash/boca/chrome_tab_strip_delegate.h"
#include "chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h"
#include "chrome/browser/ui/ash/desks/chrome_saved_desk_delegate.h"
#include "chrome/browser/ui/ash/focus_mode/chrome_focus_mode_delegate.h"
#include "chrome/browser/ui/ash/game_dashboard/chrome_game_dashboard_delegate.h"
#include "chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_ui.h"
#include "chrome/browser/ui/ash/session/session_util.h"
#include "chrome/browser/ui/ash/shell_delegate/tab_scrubber.h"
#include "chrome/browser/ui/ash/user_education/chrome_user_education_delegate.h"
#include "chrome/browser/ui/ash/wm/coral_delegate_impl.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/webui/ash/diagnostics_dialog/diagnostics_dialog.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/ash/components/audio/system_sounds_delegate_impl.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "chromeos/ash/components/channel/channel_info.h"
#include "chromeos/ash/components/specialized_features/feedback.h"
#include "chromeos/ash/experiences/clipboard/clipboard_history_controller_delegate_impl.h"
#include "chromeos/ash/experiences/clipboard/clipboard_image_model_factory_impl.h"
#include "chromeos/ash/experiences/settings_ui/settings_app_manager.h"
#include "chromeos/ash/services/multidevice_setup/multidevice_setup_service.h"
#include "components/session_manager/core/session.h"
#include "components/session_manager/core/session_manager.h"
#include "components/ui_devtools/devtools_server.h"
#include "components/ui_devtools/views/server_holder.h"
#include "components/user_manager/user_manager.h"
#include "components/version_info/channel.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/device_service.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/media_session_service.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/common/constants.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"

namespace {

const char kKeyboardShortcutHelpPageUrl[] =
    "https://support.google.com/chromebook/answer/183101";

// Browser tests are always started with --disable-logging-redirect, so we need
// independent option here.
std::optional<bool> disable_logging_redirect_for_testing;

content::WebContents* GetActiveWebContentsForNativeBrowserWindow(
    gfx::NativeWindow window) {
  ash::BrowserDelegate* browser =
      ash::BrowserController::GetInstance()->GetBrowserForWindow(window);
  return browser ? browser->GetActiveWebContents() : nullptr;
}

feedback::FeedbackSource ToChromeFeedbackSource(
    ash::ShellDelegate::FeedbackSource source) {
  switch (source) {
    case ash::ShellDelegate::FeedbackSource::kGameDashboard:
      return feedback::FeedbackSource::kFeedbackSourceGameDashboard;
    case ash::ShellDelegate::FeedbackSource::kOverview:
      return feedback::FeedbackSource::kFeedbackSourceOverview;
    case ash::ShellDelegate::FeedbackSource::kWindowLayoutMenu:
      return feedback::FeedbackSource::kFeedbackSourceWindowLayoutMenu;
    case ash::ShellDelegate::FeedbackSource::kSunfish:
      return feedback::FeedbackSource::kFeedbackSourceSunfish;
  }
  NOTREACHED() << "Unable to retrieve feedback::FeedbackSource due to "
                  "unknown source type.";
}

}  // namespace

ChromeShellDelegate::ChromeShellDelegate() {
  env_observation_.Observe(aura::Env::GetInstance());
}

ChromeShellDelegate::~ChromeShellDelegate() = default;

bool ChromeShellDelegate::CanShowWindowForUser(
    const aura::Window* window) const {
  return ::CanShowWindowForUser(window,
                                base::BindRepeating(&GetActiveBrowserContext));
}

std::unique_ptr<ash::CaptureModeDelegate>
ChromeShellDelegate::CreateCaptureModeDelegate(PrefService* local_state) const {
  // TODO(crbug.com/403153076): Remove g_browser_process usage.
  ApplicationLocaleStorage* application_locale_storage =
      g_browser_process->GetFeatures()->application_locale_storage();

  return std::make_unique<ChromeCaptureModeDelegate>(
      local_state, application_locale_storage);
}

std::unique_ptr<ash::ClipboardHistoryControllerDelegate>
ChromeShellDelegate::CreateClipboardHistoryControllerDelegate() const {
  return std::make_unique<ClipboardHistoryControllerDelegateImpl>();
}

std::unique_ptr<ash::ClipboardImageModelFactory>
ChromeShellDelegate::CreateClipboardImageModelFactory() const {
  return std::make_unique<ClipboardImageModelFactoryImpl>();
}

std::unique_ptr<ash::CoralDelegate> ChromeShellDelegate::CreateCoralDelegate()
    const {
  // TODO(crbug.com/403153076): Remove g_browser_process usage.
  ApplicationLocaleStorage* application_locale_storage =
      g_browser_process->GetFeatures()->application_locale_storage();
  variations::VariationsService* variations_service =
      g_browser_process->variations_service();
  return std::make_unique<CoralDelegateImpl>(application_locale_storage,
                                             variations_service);
}

std::unique_ptr<ash::GameDashboardDelegate>
ChromeShellDelegate::CreateGameDashboardDelegate() const {
  return std::make_unique<ChromeGameDashboardDelegate>();
}

std::unique_ptr<ash::AcceleratorPrefsDelegate>
ChromeShellDelegate::CreateAcceleratorPrefsDelegate() const {
  return std::make_unique<ChromeAcceleratorPrefsDelegate>();
}

ash::AccessibilityDelegate* ChromeShellDelegate::CreateAccessibilityDelegate() {
  return new ChromeAccessibilityDelegate;
}

std::unique_ptr<ash::BackGestureContextualNudgeDelegate>
ChromeShellDelegate::CreateBackGestureContextualNudgeDelegate(
    ash::BackGestureContextualNudgeController* controller) {
  return std::make_unique<BackGestureContextualNudgeDelegate>(controller);
}

std::unique_ptr<ash::MediaNotificationProvider>
ChromeShellDelegate::CreateMediaNotificationProvider() {
  return std::make_unique<ash::MediaNotificationProviderImpl>(
      GetMediaSessionService());
}

std::unique_ptr<ash::NearbyShareDelegate>
ChromeShellDelegate::CreateNearbyShareDelegate(
    ash::NearbyShareController* controller) const {
  return std::make_unique<NearbyShareDelegateImpl>(controller);
}

std::unique_ptr<ash::SavedDeskDelegate>
ChromeShellDelegate::CreateSavedDeskDelegate() const {
  return std::make_unique<ChromeSavedDeskDelegate>();
}

std::unique_ptr<ash::SystemSoundsDelegate>
ChromeShellDelegate::CreateSystemSoundsDelegate() const {
  return std::make_unique<SystemSoundsDelegateImpl>();
}

std::unique_ptr<ash::TabStripDelegate>
ChromeShellDelegate::CreateTabStripDelegate() const {
  return std::make_unique<ChromeTabStripDelegate>();
}

std::unique_ptr<ash::api::TasksDelegate>
ChromeShellDelegate::CreateTasksDelegate() const {
  return std::make_unique<ash::api::ChromeTasksDelegate>();
}

std::unique_ptr<ash::FocusModeDelegate>
ChromeShellDelegate::CreateFocusModeDelegate() const {
  return std::make_unique<ChromeFocusModeDelegate>();
}

std::unique_ptr<ash::UserEducationDelegate>
ChromeShellDelegate::CreateUserEducationDelegate() const {
  return std::make_unique<ChromeUserEducationDelegate>();
}

std::unique_ptr<ash::ScannerDelegate>
ChromeShellDelegate::CreateScannerDelegate() const {
  return std::make_unique<ChromeScannerDelegate>();
}

scoped_refptr<network::SharedURLLoaderFactory>
ChromeShellDelegate::GetBrowserProcessUrlLoaderFactory() const {
  return g_browser_process->shared_url_loader_factory();
}

void ChromeShellDelegate::OpenKeyboardShortcutHelpPage() const {
  ash::NewWindowDelegate::GetInstance()->OpenUrl(
      GURL(kKeyboardShortcutHelpPageUrl),
      ash::NewWindowDelegate::OpenUrlFrom::kUserInteraction,
      ash::NewWindowDelegate::Disposition::kNewForegroundTab);
}

bool ChromeShellDelegate::CanGoBack(gfx::NativeWindow window) const {
  content::WebContents* contents =
      GetActiveWebContentsForNativeBrowserWindow(window);
  return contents ? contents->GetController().CanGoBack() : false;
}

void ChromeShellDelegate::SetTabScrubberEnabled(bool enabled) {
  ash::TabScrubber::GetInstance()->SetEnabled(enabled);
}

bool ChromeShellDelegate::AllowDefaultTouchActions(gfx::NativeWindow window) {
  content::WebContents* contents =
      GetActiveWebContentsForNativeBrowserWindow(window);
  if (!contents) {
    return true;
  }
  content::RenderWidgetHostView* render_widget_host_view =
      contents->GetRenderWidgetHostView();
  if (!render_widget_host_view) {
    return true;
  }
  content::RenderWidgetHost* render_widget_host =
      render_widget_host_view->GetRenderWidgetHost();
  if (!render_widget_host) {
    return true;
  }
  std::optional<cc::TouchAction> allowed_touch_action =
      render_widget_host->GetAllowedTouchAction();
  return allowed_touch_action.has_value()
             ? *allowed_touch_action != cc::TouchAction::kNone
             : true;
}

bool ChromeShellDelegate::ShouldWaitForTouchPressAck(gfx::NativeWindow window) {
  content::WebContents* contents =
      GetActiveWebContentsForNativeBrowserWindow(window);
  if (!contents) {
    return false;
  }
  content::RenderWidgetHostView* render_widget_host_view =
      contents->GetRenderWidgetHostView();
  if (!render_widget_host_view) {
    return false;
  }
  return !!render_widget_host_view->GetRenderWidgetHost();
}

void ChromeShellDelegate::BindFingerprint(
    mojo::PendingReceiver<device::mojom::Fingerprint> receiver) {
  content::GetDeviceService().BindFingerprint(std::move(receiver));
}

void ChromeShellDelegate::BindMultiDeviceSetup(
    mojo::PendingReceiver<ash::multidevice_setup::mojom::MultiDeviceSetup>
        receiver) {
  ash::multidevice_setup::MultiDeviceSetupService* service =
      ash::multidevice_setup::MultiDeviceSetupServiceFactory::GetForProfile(
          ProfileManager::GetPrimaryUserProfile());
  if (service) {
    service->BindMultiDeviceSetup(std::move(receiver));
  }
}

media_session::MediaSessionService*
ChromeShellDelegate::GetMediaSessionService() {
  return &content::GetMediaSessionService();
}

bool ChromeShellDelegate::IsSessionRestoreInProgress() const {
  // Must be called with an active user.
  const user_manager::User* active_user =
      user_manager::UserManager::Get()->GetActiveUser();
  CHECK(active_user);

  // User profile is not yet loaded. Consider loading user profile is part of
  // session restore.
  if (!active_user->is_profile_created()) {
    return true;
  }

  return SessionRestore::IsRestoring(Profile::FromBrowserContext(
      ash::BrowserContextHelper::Get()->GetBrowserContextByUser(active_user)));
}

void ChromeShellDelegate::SetUpEnvironmentForLockedFullscreen(
    const ash::WindowState& window_state) {
  const bool locked = window_state.IsPinned();
  // Reset the clipboard and kill dev tools when entering or exiting locked
  // fullscreen (security concerns).
  if (locked) {
    ash::ClipboardImageModelFactory::Get()->CancelAllRequests();
  }
  ui::Clipboard::GetForCurrentThread()->Clear(ui::ClipboardBuffer::kCopyPaste);
  content::DevToolsAgentHost::DetachAllClients();

  // TODO(crbug.com/40195284): This might be interesting for DLP to change.
  // Disable both screenshots and video screen captures via the capture mode
  // feature.
  ChromeCaptureModeDelegate::Get()->SetIsScreenCaptureLocked(locked);

  // Get the primary profile as that's what ARC and Assistant are attached to.
  const Profile* const profile = ProfileManager::GetPrimaryUserProfile();
  // Commands below require profile.
  if (!profile) {
    return;
  }

  arc::ArcServiceLauncher* const arc_service_launcher =
      arc::ArcServiceLauncher::Get();
  if (arc_service_launcher &&
      arc_service_launcher->arc_locked_fullscreen_manager() &&
      !ash::IsArcWindow(window_state.window()) &&
      arc::IsArcAllowedForProfile(profile)) {
    arc_service_launcher->arc_locked_fullscreen_manager()
        ->UpdateForLockedFullscreenMode(locked);
  }

  // If a window is entering locked fullscreen, then we should close any
  // diagnostics dialog that may be open, since it would show on top of the
  // fullscreen window. There is no need to close it when leaving locked
  // fullscreen, since it is OK for the dialog to be open after exiting locked
  // fullscreen in case the dialog was somehow opened during locked fullscreen.
  if (locked) {
    ash::DiagnosticsDialog::MaybeCloseExistingDialog();
  }
}

bool ChromeShellDelegate::IsUiDevToolsStarted() const {
  return ui_devtools::ServerHolder::GetInstance()
      ->GetUiDevToolsServerInstance();
}

void ChromeShellDelegate::StartUiDevTools() {
  base::FilePath output_dir;
  bool result = base::PathService::Get(chrome::DIR_USER_DATA, &output_dir);
  DCHECK(result);

  return ui_devtools::ServerHolder::GetInstance()->CreateUiDevTools(output_dir);
}

void ChromeShellDelegate::StopUiDevTools() {
  return ui_devtools::ServerHolder::GetInstance()->DestroyUiDevTools();
}

int ChromeShellDelegate::GetUiDevToolsPort() const {
  return ui_devtools::ServerHolder::GetInstance()
      ->GetUiDevToolsServerInstance()
      ->port();
}

bool ChromeShellDelegate::IsLoggingRedirectDisabled() const {
  if (disable_logging_redirect_for_testing.has_value()) {
    return disable_logging_redirect_for_testing.value();
  }

  return base::CommandLine::ForCurrentProcess()->HasSwitch(
      ash::switches::kDisableLoggingRedirect);
}

base::FilePath ChromeShellDelegate::GetPrimaryUserDownloadsFolder() const {
  const user_manager::User* primary_user =
      user_manager::UserManager::Get()->GetPrimaryUser();
  if (!primary_user) {
    return base::FilePath();
  }

  content::BrowserContext* browser_context =
      ash::BrowserContextHelper::Get()->GetBrowserContextByUser(primary_user);
  if (browser_context) {
    return file_manager::util::GetDownloadsFolderForProfile(
        Profile::FromBrowserContext(browser_context));
  }

  return base::FilePath();
}

void ChromeShellDelegate::OpenFeedbackDialog(
    ShellDelegate::FeedbackSource source,
    const std::string& description_template,
    const std::string& category_tag) {
  chrome::OpenFeedbackDialog(/*browser=*/nullptr,
                             ToChromeFeedbackSource(source),
                             description_template, category_tag);
}

bool ChromeShellDelegate::SendSpecializedFeatureFeedback(
    const AccountId& account_id,
    int product_id,
    std::string description,
    std::optional<std::string> image,
    std::optional<std::string> image_mime_type) {
  // NOTE: `FeedbackUploaderFactoryChrome` (in //chrome/browser/feedback/)
  // returns different instances to `FeedbackUploaderFactory` (in
  // //components/feedback/content). The correct instance should be obtained
  // from `FeedbackUploaderFactoryChrome`.
  content::BrowserContext* browser_context =
      ash::BrowserContextHelper::Get()->GetBrowserContextByAccountId(
          account_id);
  if (!browser_context) {
    return false;
  }

  feedback::FeedbackUploaderChrome* uploader =
      feedback::FeedbackUploaderFactoryChrome::GetForBrowserContext(
          browser_context);
  if (!uploader) {
    return false;
  }

  specialized_features::SendFeedback(*uploader, product_id,
                                     std::move(description), std::move(image),
                                     std::move(image_mime_type));
  return true;
}

void ChromeShellDelegate::OpenProfileManager() {
  NOTREACHED();
}

// static
void ChromeShellDelegate::SetDisableLoggingRedirectForTesting(bool value) {
  disable_logging_redirect_for_testing = value;
}

// static
void ChromeShellDelegate::ResetDisableLoggingRedirectForTesting() {
  disable_logging_redirect_for_testing.reset();
}

const GURL& ChromeShellDelegate::GetLastCommittedURLForWindowIfAny(
    aura::Window* window) {
  // Get the web content if the window is a browser window.
  content::WebContents* contents =
      GetActiveWebContentsForNativeBrowserWindow(window);

  if (!contents) {
    // Get the web content if the window is an app window.
    Profile* profile = ProfileManager::GetLastUsedProfile();
    if (profile) {
      const extensions::AppWindow* app_window =
          extensions::AppWindowRegistry::Get(profile)
              ->GetAppWindowForNativeWindow(window);
      if (app_window) {
        contents = app_window->web_contents();
      }
    }
  }

  return contents ? contents->GetLastCommittedURL() : GURL::EmptyGURL();
}

version_info::Channel ChromeShellDelegate::GetChannel() {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          ash::switches::kForceShowReleaseTrack)) {
    // Simulate a non-stable channel so the release track UI is visible.
    return version_info::Channel::BETA;
  }
  return ash::GetChannel();
}

void ChromeShellDelegate::ForceSkipWarningUserOnClose(
    const std::vector<raw_ptr<aura::Window, VectorExperimental>>& windows) {
  for (aura::Window* window : windows) {
    ash::BrowserDelegate* browser =
        ash::BrowserController::GetInstance()->GetBrowserForWindow(window);
    if (browser) {
      browser->SetSkipWarningUserOnClose(true);
    }
  }
}

void ChromeShellDelegate::OnPostWindowStateTypeChange(
    ash::WindowState* window_state,
    chromeos::WindowStateType old_type) {
  // Register/unregister the PiP widget with the occlusion tracker. This ensures
  // that permission prompts can detect when they are occluded by this PiP
  // window and apply clickjacking protections.
  // Note: These calls may be redundant for native Chrome PiP windows which
  // already register themselves, but are necessary for Exo-hosted windows.
  PictureInPictureOcclusionTracker* tracker =
      PictureInPictureWindowManager::GetInstance()->GetOcclusionTracker();
  if (!tracker) {
    return;
  }

  if (window_state->IsPip()) {
    if (auto* widget =
            views::Widget::GetWidgetForNativeWindow(window_state->window())) {
      tracker->OnPictureInPictureWidgetOpened(widget);
    }
  } else if (old_type == chromeos::WindowStateType::kPip) {
    if (auto* widget =
            views::Widget::GetWidgetForNativeWindow(window_state->window())) {
      tracker->RemovePictureInPictureWidget(widget);
    }
  }
}

void ChromeShellDelegate::OnWindowInitialized(aura::Window* window) {
  observed_windows_.AddObservation(window);
  if (auto* window_state = window->GetProperty(ash::kWindowStateKey)) {
    MaybeObserveWindowState(window_state);
  }
}

void ChromeShellDelegate::OnWindowPropertyChanged(aura::Window* window,
                                                  const void* key,
                                                  intptr_t old) {
  if (key == ash::kWindowStateKey) {
    if (auto* window_state = window->GetProperty(ash::kWindowStateKey)) {
      MaybeObserveWindowState(window_state);
    }
  }
}

void ChromeShellDelegate::OnWindowDestroying(aura::Window* window) {
  if (auto* window_state = window->GetProperty(ash::kWindowStateKey)) {
    if (observed_window_states_.IsObservingSource(window_state)) {
      observed_window_states_.RemoveObservation(window_state);
    }
  }

  if (observed_windows_.IsObservingSource(window)) {
    observed_windows_.RemoveObservation(window);
  }
}

void ChromeShellDelegate::MaybeObserveWindowState(
    ash::WindowState* window_state) {
  if (!observed_window_states_.IsObservingSource(window_state)) {
    observed_window_states_.AddObservation(window_state);

    // If the window is already in PiP, register it.
    if (window_state->IsPip()) {
      OnPostWindowStateTypeChange(window_state,
                                  chromeos::WindowStateType::kDefault);
    }
  }
}

std::string ChromeShellDelegate::GetVersionString() {
  return std::string(version_info::GetVersionNumber());
}

void ChromeShellDelegate::OpenMultitaskingSettings() {
  auto* session = session_manager::SessionManager::Get()->GetActiveSession();
  if (!session) {
    // TODO(crbug.com/447287122): Revisit here to see if there always is
    // an active session.
    return;
  }
  ash::SettingsAppManager::Get()->Open(
      CHECK_DEREF(
          user_manager::UserManager::Get()->FindUser(session->account_id())),
      {.sub_page = chromeos::settings::mojom::kSystemPreferencesSectionPath,
       .setting_id =
           chromeos::settings::mojom::Setting::kSnapWindowSuggestions});
}

bool ChromeShellDelegate::IsNoFirstRunSwitchOn() const {
  return base::CommandLine::ForCurrentProcess()->HasSwitch(
      ::switches::kNoFirstRun);
}
