// 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 "ash/shell.h"

#include <algorithm>
#include <memory>
#include <string>
#include <utility>

#include "ash/accelerators/accelerator_controller_impl.h"
#include "ash/accelerators/accelerator_tracker.h"
#include "ash/accelerators/ash_accelerator_configuration.h"
#include "ash/accelerators/ash_focus_manager_factory.h"
#include "ash/accelerators/magnifier_key_scroller.h"
#include "ash/accelerators/pre_target_accelerator_handler.h"
#include "ash/accelerators/spoken_feedback_toggler.h"
#include "ash/accelerometer/accelerometer_reader.h"
#include "ash/accessibility/accessibility_controller_impl.h"
#include "ash/accessibility/accessibility_delegate.h"
#include "ash/accessibility/autoclick/autoclick_controller.h"
#include "ash/accessibility/chromevox/key_accessibility_enabler.h"
#include "ash/accessibility/magnifier/docked_magnifier_controller.h"
#include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h"
#include "ash/accessibility/magnifier/partial_magnifier_controller.h"
#include "ash/accessibility/sticky_keys/sticky_keys_controller.h"
#include "ash/accessibility/ui/accessibility_focus_ring_controller_impl.h"
#include "ash/ambient/ambient_controller.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/app_list/app_list_feature_usage_metrics.h"
#include "ash/assistant/assistant_controller_impl.h"
#include "ash/calendar/calendar_controller.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/child_accounts/parent_access_controller_impl.h"
#include "ash/clipboard/clipboard_history_controller_impl.h"
#include "ash/clipboard/control_v_histogram_recorder.h"
#include "ash/color_enhancement/color_enhancement_controller.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "ash/controls/contextual_tooltip.h"
#include "ash/curtain/security_curtain_controller_impl.h"
#include "ash/dbus/ash_dbus_services.h"
#include "ash/detachable_base/detachable_base_handler.h"
#include "ash/detachable_base/detachable_base_notification_controller.h"
#include "ash/display/cros_display_config.h"
#include "ash/display/cursor_window_controller.h"
#include "ash/display/display_alignment_controller.h"
#include "ash/display/display_color_manager.h"
#include "ash/display/display_configuration_controller.h"
#include "ash/display/display_configuration_observer.h"
#include "ash/display/display_error_observer.h"
#include "ash/display/display_highlight_controller.h"
#include "ash/display/display_prefs.h"
#include "ash/display/display_shutdown_observer.h"
#include "ash/display/event_transformation_handler.h"
#include "ash/display/mouse_cursor_event_filter.h"
#include "ash/display/privacy_screen_controller.h"
#include "ash/display/projecting_observer.h"
#include "ash/display/refresh_rate_throttle_controller.h"
#include "ash/display/resolution_notification_controller.h"
#include "ash/display/screen_ash.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/display/screen_position_controller.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/drag_drop/drag_drop_controller.h"
#include "ash/events/event_rewriter_controller_impl.h"
#include "ash/events/keyboard_capability_delegate_impl.h"
#include "ash/fast_ink/laser/laser_pointer_controller.h"
#include "ash/focus_cycler.h"
#include "ash/frame/non_client_frame_view_ash.h"
#include "ash/frame/snap_controller_impl.h"
#include "ash/frame_throttler/frame_throttling_controller.h"
#include "ash/game_dashboard/game_dashboard_controller.h"
#include "ash/glanceables/glanceables_controller.h"
#include "ash/glanceables/glanceables_delegate.h"
#include "ash/glanceables/glanceables_v2_controller.h"
#include "ash/host/ash_window_tree_host_init_params.h"
#include "ash/hud_display/hud_display.h"
#include "ash/ime/ime_controller_impl.h"
#include "ash/in_session_auth/in_session_auth_dialog_controller_impl.h"
#include "ash/in_session_auth/webauthn_dialog_controller_impl.h"
#include "ash/keyboard/keyboard_controller_impl.h"
#include "ash/keyboard/ui/keyboard_ui_factory.h"
#include "ash/login/login_screen_controller.h"
#include "ash/login_status.h"
#include "ash/media/media_controller_impl.h"
#include "ash/metrics/feature_discovery_duration_reporter_impl.h"
#include "ash/metrics/login_unlock_throughput_recorder.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/multi_capture/multi_capture_service_client.h"
#include "ash/multi_device_setup/multi_device_notification_presenter.h"
#include "ash/policy/policy_recommendation_restorer.h"
#include "ash/projector/projector_controller_impl.h"
#include "ash/public/cpp/accelerator_keycode_lookup_cache.h"
#include "ash/public/cpp/ash_prefs.h"
#include "ash/public/cpp/holding_space/holding_space_controller.h"
#include "ash/public/cpp/nearby_share_delegate.h"
#include "ash/public/cpp/saved_desk_delegate.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/public/cpp/shelf_model.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/system_sounds_delegate.h"
#include "ash/public/cpp/tab_cluster/tab_cluster_ui_controller.h"
#include "ash/public/cpp/views_text_services_context_menu_ash.h"
#include "ash/quick_pair/keyed_service/quick_pair_mediator.h"
#include "ash/rgb_keyboard/rgb_keyboard_manager.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/shelf_controller.h"
#include "ash/shelf/shelf_window_watcher.h"
#include "ash/shell_delegate.h"
#include "ash/shell_init_params.h"
#include "ash/shell_observer.h"
#include "ash/shell_tab_handler.h"
#include "ash/shutdown_controller_impl.h"
#include "ash/style/ash_color_mixer.h"
#include "ash/style/ash_color_provider.h"
#include "ash/style/color_palette_controller.h"
#include "ash/style/dark_light_mode_controller_impl.h"
#include "ash/style/style_util.h"
#include "ash/system/audio/audio_effects_controller.h"
#include "ash/system/audio/display_speaker_controller.h"
#include "ash/system/bluetooth/bluetooth_device_status_ui_handler.h"
#include "ash/system/bluetooth/bluetooth_notification_controller.h"
#include "ash/system/bluetooth/bluetooth_state_cache.h"
#include "ash/system/brightness/brightness_controller_chromeos.h"
#include "ash/system/brightness_control_delegate.h"
#include "ash/system/camera/autozoom_controller_impl.h"
#include "ash/system/camera/camera_effects_controller.h"
#include "ash/system/caps_lock_notification_controller.h"
#include "ash/system/diagnostics/diagnostics_log_controller.h"
#include "ash/system/federated/federated_service_controller_impl.h"
#include "ash/system/firmware_update/firmware_update_notification_controller.h"
#include "ash/system/geolocation/geolocation_controller.h"
#include "ash/system/human_presence/human_presence_orientation_controller.h"
#include "ash/system/human_presence/snooping_protection_controller.h"
#include "ash/system/input_device_settings/input_device_key_alias_manager.h"
#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
#include "ash/system/input_device_settings/input_device_settings_dispatcher.h"
#include "ash/system/input_device_settings/input_device_tracker.h"
#include "ash/system/input_device_settings/keyboard_modifier_metrics_recorder.h"
#include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
#include "ash/system/keyboard_brightness/keyboard_brightness_controller.h"
#include "ash/system/keyboard_brightness_control_delegate.h"
#include "ash/system/locale/locale_update_controller_impl.h"
#include "ash/system/media/media_notification_provider.h"
#include "ash/system/message_center/message_center_ash_impl.h"
#include "ash/system/message_center/message_center_controller.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/model/virtual_keyboard_model.h"
#include "ash/system/nearby_share/nearby_share_controller_impl.h"
#include "ash/system/network/sms_observer.h"
#include "ash/system/night_light/night_light_controller_impl.h"
#include "ash/system/pcie_peripheral/pcie_peripheral_notification_controller.h"
#include "ash/system/power/adaptive_charging_controller.h"
#include "ash/system/power/backlights_forced_off_setter.h"
#include "ash/system/power/peripheral_battery_notifier.h"
#include "ash/system/power/power_button_controller.h"
#include "ash/system/power/power_event_observer.h"
#include "ash/system/power/power_prefs.h"
#include "ash/system/power/power_status.h"
#include "ash/system/power/video_activity_notifier.h"
#include "ash/system/privacy/screen_switch_check_controller.h"
#include "ash/system/privacy_hub/privacy_hub_controller.h"
#include "ash/system/screen_layout_observer.h"
#include "ash/system/session/logout_confirmation_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/system_notification_controller.h"
#include "ash/system/toast/toast_manager_impl.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/usb_peripheral/usb_peripheral_notification_controller.h"
#include "ash/system/video_conference/fake_video_conference_tray_controller.h"
#include "ash/touch/ash_touch_transform_controller.h"
#include "ash/touch/touch_devices_controller.h"
#include "ash/touch/touch_selection_magnifier_runner_ash.h"
#include "ash/tray_action/tray_action.h"
#include "ash/user_education/user_education_controller.h"
#include "ash/user_education/user_education_delegate.h"
#include "ash/utility/occlusion_tracker_pauser.h"
#include "ash/wallpaper/wallpaper_controller_impl.h"
#include "ash/wm/ash_focus_rules.h"
#include "ash/wm/container_finder.h"
#include "ash/wm/cursor_manager_chromeos.h"
#include "ash/wm/desks/desks_controller.h"
#include "ash/wm/desks/templates/saved_desk_controller.h"
#include "ash/wm/event_client_impl.h"
#include "ash/wm/float/float_controller.h"
#include "ash/wm/gestures/back_gesture/back_gesture_event_handler.h"
#include "ash/wm/immersive_context_ash.h"
#include "ash/wm/lock_state_controller.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/multi_display/multi_display_metrics_controller.h"
#include "ash/wm/multi_display/persistent_window_controller.h"
#include "ash/wm/multitask_menu_nudge_delegate_ash.h"
#include "ash/wm/native_cursor_manager_ash.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/raster_scale_controller.h"
#include "ash/wm/resize_shadow_controller.h"
#include "ash/wm/screen_pinning_controller.h"
#include "ash/wm/snap_group/snap_group_controller.h"
#include "ash/wm/system_gesture_event_filter.h"
#include "ash/wm/system_modal_container_event_filter.h"
#include "ash/wm/system_modal_container_layout_manager.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
#include "ash/wm/toplevel_window_event_handler.h"
#include "ash/wm/video_detector.h"
#include "ash/wm/window_animations.h"
#include "ash/wm/window_cycle/window_cycle_controller.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_restore/window_restore_controller.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_shadow_controller_delegate.h"
#include "ash/wm/workspace_controller.h"
#include "ash/wm_mode/wm_mode_controller.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/system/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "chromeos/ash/components/dbus/fwupd/fwupd_client.h"
#include "chromeos/ash/components/dbus/usb/usbguard_client.h"
#include "chromeos/ash/components/fwupd/firmware_update_manager.h"
#include "chromeos/ash/components/peripheral_notification/peripheral_notification_manager.h"
#include "chromeos/ash/services/assistant/public/cpp/features.h"
#include "chromeos/dbus/init/initialize_dbus_client.h"
#include "chromeos/dbus/power/power_policy_controller.h"
#include "chromeos/ui/wm/features.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "dbus/bus.h"
#include "media/capture/video/chromeos/video_capture_features_chromeos.h"
#include "services/video_capture/public/mojom/multi_capture_service.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/chromeos/user_activity_power_manager_notifier.h"
#include "ui/color/color_provider_manager.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/display/display.h"
#include "ui/display/manager/default_touch_transform_setter.h"
#include "ui/display/manager/display_change_observer.h"
#include "ui/display/manager/display_configurator.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/manager/touch_transform_setter.h"
#include "ui/display/screen.h"
#include "ui/display/types/native_display_delegate.h"
#include "ui/events/ash/keyboard_capability.h"
#include "ui/events/event_target_iterator.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/message_center/message_center.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/views/controls/views_text_services_context_menu_chromeos.h"
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/corewm/tooltip_controller.h"
#include "ui/views/focus/focus_manager_factory.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/accelerator_filter.h"
#include "ui/wm/core/compound_event_filter.h"
#include "ui/wm/core/focus_controller.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/visibility_controller.h"
#include "ui/wm/core/window_modality_controller.h"

namespace ash {

namespace {

using aura::Window;
using views::Widget;

// A Corewm VisibilityController subclass that calls the Ash animation routine
// so we can pick up our extended animations. See ash/wm/window_animations.h.
class AshVisibilityController : public ::wm::VisibilityController {
 public:
  AshVisibilityController() = default;

  AshVisibilityController(const AshVisibilityController&) = delete;
  AshVisibilityController& operator=(const AshVisibilityController&) = delete;

  ~AshVisibilityController() override = default;

 private:
  // Overridden from ::wm::VisibilityController:
  bool CallAnimateOnChildWindowVisibilityChanged(aura::Window* window,
                                                 bool visible) override {
    return AnimateOnChildWindowVisibilityChanged(window, visible);
  }
};

}  // namespace

// static
Shell* Shell::instance_ = nullptr;

////////////////////////////////////////////////////////////////////////////////
// Shell, public:

// static
Shell* Shell::CreateInstance(ShellInitParams init_params) {
  CHECK(!instance_);
  instance_ = new Shell(std::move(init_params.delegate));
  instance_->Init(init_params.context_factory, init_params.local_state,
                  std::move(init_params.keyboard_ui_factory),
                  init_params.dbus_bus);
  return instance_;
}

// static
Shell* Shell::Get() {
  CHECK(instance_);
  return instance_;
}

// static
bool Shell::HasInstance() {
  return !!instance_;
}

// static
void Shell::DeleteInstance() {
  delete instance_;
}

// static
RootWindowController* Shell::GetPrimaryRootWindowController() {
  CHECK(HasInstance());
  return RootWindowController::ForWindow(GetPrimaryRootWindow());
}

// static
Shell::RootWindowControllerList Shell::GetAllRootWindowControllers() {
  CHECK(HasInstance());
  RootWindowControllerList root_window_controllers;
  for (aura::Window* root : GetAllRootWindows()) {
    root_window_controllers.push_back(RootWindowController::ForWindow(root));
  }
  return root_window_controllers;
}

// static
RootWindowController* Shell::GetRootWindowControllerWithDisplayId(
    int64_t display_id) {
  CHECK(HasInstance());
  aura::Window* root = GetRootWindowForDisplayId(display_id);
  return root ? RootWindowController::ForWindow(root) : nullptr;
}

// static
aura::Window* Shell::GetRootWindowForDisplayId(int64_t display_id) {
  CHECK(HasInstance());
  return instance_->window_tree_host_manager_->GetRootWindowForDisplayId(
      display_id);
}

// static
aura::Window* Shell::GetPrimaryRootWindow() {
  CHECK(HasInstance());
  return instance_->window_tree_host_manager_->GetPrimaryRootWindow();
}

// static
void Shell::SetRootWindowForNewWindows(aura::Window* root) {
  display::Screen::GetScreen()->SetDisplayForNewWindows(
      display::Screen::GetScreen()->GetDisplayNearestWindow(root).id());
}

// static
aura::Window* Shell::GetRootWindowForNewWindows() {
  return GetRootWindowForDisplayId(
      display::Screen::GetScreen()->GetDisplayForNewWindows().id());
}

// static
aura::Window::Windows Shell::GetAllRootWindows() {
  CHECK(HasInstance());
  return instance_->window_tree_host_manager_->GetAllRootWindows();
}

// static
aura::Window* Shell::GetContainer(aura::Window* root_window, int container_id) {
  return root_window->GetChildById(container_id);
}

// static
const aura::Window* Shell::GetContainer(const aura::Window* root_window,
                                        int container_id) {
  return root_window->GetChildById(container_id);
}

// static
int Shell::GetOpenSystemModalWindowContainerId() {
  // The test boolean is not static to avoid leaking state between tests.
  if (Get()->simulate_modal_window_open_for_test_) {
    return kShellWindowId_SystemModalContainer;
  }

  // Traverse all system modal containers, and find its direct child window
  // with "SystemModal" setting, and visible.
  for (aura::Window* root : Shell::GetAllRootWindows()) {
    for (int modal_window_id : kSystemModalContainerIds) {
      aura::Window* system_modal = root->GetChildById(modal_window_id);
      if (!system_modal) {
        continue;
      }
      for (const aura::Window* child : system_modal->children()) {
        if (child->GetProperty(aura::client::kModalKey) ==
                ui::MODAL_TYPE_SYSTEM &&
            child->layer()->GetTargetVisibility()) {
          return modal_window_id;
        }
      }
    }
  }
  return -1;
}

// static
bool Shell::IsSystemModalWindowOpen() {
  return GetOpenSystemModalWindowContainerId() >= 0;
}

display::DisplayConfigurator* Shell::display_configurator() {
  return display_manager_->configurator();
}

void Shell::TrackInputMethodBounds(ArcInputMethodBoundsTracker* tracker) {
  system_tray_model()->virtual_keyboard()->SetInputMethodBoundsTrackerObserver(
      tracker);
}

void Shell::UntrackTrackInputMethodBounds(
    ArcInputMethodBoundsTracker* tracker) {
  system_tray_model()
      ->virtual_keyboard()
      ->RemoveInputMethodBoundsTrackerObserver(tracker);
}

std::unique_ptr<views::NonClientFrameView>
Shell::CreateDefaultNonClientFrameView(views::Widget* widget) {
  // Use translucent-style window frames for dialogs.
  return std::make_unique<NonClientFrameViewAsh>(widget);
}

void Shell::OnCastingSessionStartedOrStopped(bool started) {
  for (auto& observer : shell_observers_) {
    observer.OnCastingSessionStartedOrStopped(started);
  }
}

void Shell::OnRootWindowAdded(aura::Window* root_window) {
  for (auto& observer : shell_observers_) {
    observer.OnRootWindowAdded(root_window);
  }
}

void Shell::OnRootWindowWillShutdown(aura::Window* root_window) {
  DCHECK(toplevel_window_event_handler_);
  root_window->RemovePreTargetHandler(toplevel_window_event_handler_.get());
  root_window->RemovePostTargetHandler(toplevel_window_event_handler_.get());

  for (auto& observer : shell_observers_) {
    observer.OnRootWindowWillShutdown(root_window);
  }
}

void Shell::OnDictationStarted() {
  for (auto& observer : shell_observers_) {
    observer.OnDictationStarted();
  }
}

void Shell::OnDictationEnded() {
  for (auto& observer : shell_observers_) {
    observer.OnDictationEnded();
  }
}

bool Shell::IsInTabletMode() const {
  return tablet_mode_controller()->InTabletMode();
}

bool Shell::ShouldSaveDisplaySettings() {
  return !(
      screen_orientation_controller_->ignore_display_configuration_updates() ||
      // Save display settings if we don't need to show the display change
      // dialog.
      resolution_notification_controller_->ShouldShowDisplayChangeDialog());
}

::wm::ActivationClient* Shell::activation_client() {
  return focus_controller_.get();
}

bool Shell::HasPrimaryStatusArea() {
  return !!GetPrimaryRootWindowController()->GetStatusAreaWidget();
}

void Shell::SetLargeCursorSizeInDip(int large_cursor_size_in_dip) {
  window_tree_host_manager_->cursor_window_controller()
      ->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
}

void Shell::SetCursorColor(SkColor cursor_color) {
  window_tree_host_manager_->cursor_window_controller()->SetCursorColor(
      cursor_color);
}

void Shell::UpdateCursorCompositingEnabled() {
  SetCursorCompositingEnabled(
      window_tree_host_manager_->cursor_window_controller()
          ->ShouldEnableCursorCompositing());
}

void Shell::SetCursorCompositingEnabled(bool enabled) {
  CursorWindowController* cursor_window_controller =
      window_tree_host_manager_->cursor_window_controller();

  if (cursor_window_controller->is_cursor_compositing_enabled() == enabled) {
    return;
  }
  cursor_window_controller->SetCursorCompositingEnabled(enabled);
  native_cursor_manager_->SetNativeCursorEnabled(!enabled);
}

void Shell::DoInitialWorkspaceAnimation() {
  // Uses the active desk's workspace.
  auto* workspace = GetActiveWorkspaceController(GetPrimaryRootWindow());
  DCHECK(workspace);
  workspace->DoInitialAnimation();
}

void Shell::ShowContextMenu(const gfx::Point& location_in_screen,
                            ui::MenuSourceType source_type) {
  // Bail with no active user session, in the lock screen, or in app/kiosk mode.
  if (session_controller_->NumberOfLoggedInUsers() < 1 ||
      session_controller_->IsScreenLocked() ||
      session_controller_->IsRunningInAppMode()) {
    return;
  }

  aura::Window* root = window_util::GetRootWindowAt(location_in_screen);
  RootWindowController::ForWindow(root)->ShowContextMenu(location_in_screen,
                                                         source_type);
}

void Shell::AddShellObserver(ShellObserver* observer) {
  shell_observers_.AddObserver(observer);
}

void Shell::RemoveShellObserver(ShellObserver* observer) {
  shell_observers_.RemoveObserver(observer);
}

void Shell::ShutdownEventDispatch() {
  for (aura::Window* root : GetAllRootWindows()) {
    aura::client::SetDragDropClient(root, nullptr);
  }

  // Stop dispatching events (e.g. synthesized mouse exits from window close).
  // https://crbug.com/874156
  for (RootWindowController* rwc : GetAllRootWindowControllers()) {
    rwc->GetHost()->dispatcher()->Shutdown();
  }
}

void Shell::UpdateAfterLoginStatusChange(LoginStatus status) {
  for (auto* root_window_controller : GetAllRootWindowControllers()) {
    root_window_controller->UpdateAfterLoginStatusChange(status);
  }
}

void Shell::NotifyFullscreenStateChanged(bool is_fullscreen,
                                         aura::Window* container) {
  for (auto& observer : shell_observers_) {
    observer.OnFullscreenStateChanged(is_fullscreen, container);
  }
}

void Shell::NotifyPinnedStateChanged(aura::Window* pinned_window) {
  for (auto& observer : shell_observers_) {
    observer.OnPinnedStateChanged(pinned_window);
  }
}

void Shell::NotifyUserWorkAreaInsetsChanged(aura::Window* root_window) {
  for (auto& observer : shell_observers_) {
    observer.OnUserWorkAreaInsetsChanged(root_window);
  }
}

void Shell::NotifyShelfAlignmentChanged(aura::Window* root_window,
                                        ShelfAlignment old_alignment) {
  for (auto& observer : shell_observers_) {
    observer.OnShelfAlignmentChanged(root_window, old_alignment);
  }
}

void Shell::NotifyDisplayForNewWindowsChanged() {
  for (auto& observer : shell_observers_) {
    observer.OnDisplayForNewWindowsChanged();
  }
}

void Shell::AddAccessibilityEventHandler(
    ui::EventHandler* handler,
    AccessibilityEventHandlerManager::HandlerType type) {
  if (!accessibility_event_handler_manager_) {
    accessibility_event_handler_manager_ =
        std::make_unique<AccessibilityEventHandlerManager>();
  }

  accessibility_event_handler_manager_->AddAccessibilityEventHandler(handler,
                                                                     type);
}
void Shell::RemoveAccessibilityEventHandler(ui::EventHandler* handler) {
  accessibility_event_handler_manager_->RemoveAccessibilityEventHandler(
      handler);
}

////////////////////////////////////////////////////////////////////////////////
// Shell, private:

Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate)
    : brightness_control_delegate_(
          std::make_unique<system::BrightnessControllerChromeos>()),
      focus_cycler_(std::make_unique<FocusCycler>()),
      ime_controller_(std::make_unique<ImeControllerImpl>()),
      immersive_context_(std::make_unique<ImmersiveContextAsh>()),
      webauthn_dialog_controller_(
          std::make_unique<WebAuthNDialogControllerImpl>()),
      in_session_auth_dialog_controller_(
          std::make_unique<InSessionAuthDialogControllerImpl>()),
      keyboard_brightness_control_delegate_(
          std::make_unique<KeyboardBrightnessController>()),
      locale_update_controller_(std::make_unique<LocaleUpdateControllerImpl>()),
      parent_access_controller_(std::make_unique<ParentAccessControllerImpl>()),
      session_controller_(std::make_unique<SessionControllerImpl>()),
      feature_discover_reporter_(
          std::make_unique<FeatureDiscoveryDurationReporterImpl>(
              session_controller_.get())),
      shell_delegate_(std::move(shell_delegate)),
      shutdown_controller_(std::make_unique<ShutdownControllerImpl>()),
      system_tray_notifier_(std::make_unique<SystemTrayNotifier>()),
      native_cursor_manager_(nullptr) {
  AccelerometerReader::GetInstance()->Initialize();

  login_screen_controller_ =
      std::make_unique<LoginScreenController>(system_tray_notifier_.get());
  display_manager_ = ScreenAsh::CreateDisplayManager();
  window_tree_host_manager_ = std::make_unique<WindowTreeHostManager>();
  user_metrics_recorder_ = std::make_unique<UserMetricsRecorder>();
  keyboard_controller_ =
      std::make_unique<KeyboardControllerImpl>(session_controller_.get());

  PowerStatus::Initialize();

  session_controller_->AddObserver(this);
}

Shell::~Shell() {
  TRACE_EVENT0("shutdown", "ash::Shell::Destructor");
#if DCHECK_IS_ON()
  // All WindowEventDispatchers should be shutdown before the Shell is
  // destroyed.
  for (RootWindowController* rwc : GetAllRootWindowControllers()) {
    DCHECK(rwc->GetHost()->dispatcher()->in_shutdown());
  }
#endif
  login_unlock_throughput_recorder_.reset();

  hud_display::HUDDisplayView::Destroy();

  // Observes `SessionController` and must be destroyed before it.
  privacy_hub_controller_.reset();
  microphone_privacy_switch_controller_.reset();

  for (auto& observer : shell_observers_) {
    observer.OnShellDestroying();
  }

  ash_dbus_services_.reset();

  saved_desk_controller_.reset();
  saved_desk_delegate_.reset();
  desks_controller_->Shutdown();

  user_metrics_recorder_->OnShellShuttingDown();

  cros_display_config_.reset();
  display_configuration_observer_.reset();
  display_prefs_.reset();
  display_alignment_controller_.reset();
  refresh_rate_throttle_controller_.reset();

  // Remove the focus from any window. This will prevent overhead and side
  // effects (e.g. crashes) from changing focus during shutdown.
  // See bug crbug.com/134502.
  aura::client::GetFocusClient(GetPrimaryRootWindow())->FocusWindow(nullptr);

  // Please keep in reverse order as in Init() because it's easy to miss one.
  if (window_modality_controller_) {
    window_modality_controller_.reset();
  }

  RemovePreTargetHandler(shell_tab_handler_.get());
  shell_tab_handler_.reset();

  RemovePreTargetHandler(magnifier_key_scroll_handler_.get());
  magnifier_key_scroll_handler_.reset();

  RemovePreTargetHandler(speech_feedback_handler_.get());
  speech_feedback_handler_.reset();

  RemovePreTargetHandler(control_v_histogram_recorder_.get());
  RemovePreTargetHandler(accelerator_tracker_.get());
  RemovePreTargetHandler(accelerator_filter_.get());
  RemovePreTargetHandler(event_transformation_handler_.get());
  if (back_gesture_event_handler_) {
    RemovePreTargetHandler(back_gesture_event_handler_.get());
  }
  RemovePreTargetHandler(system_gesture_filter_.get());
  RemoveAccessibilityEventHandler(mouse_cursor_filter_.get());
  RemovePreTargetHandler(modality_filter_.get());
  RemovePreTargetHandler(tooltip_controller_.get());

  // Resets the text context menu implementation factory.
  views::ViewsTextServicesContextMenuChromeos::SetImplFactory(
      base::NullCallback());

  wm_mode_controller_.reset();

  event_rewriter_controller_.reset();
  keyboard_modifier_metrics_recorder_.reset();
  input_device_settings_dispatcher_.reset();
  input_device_tracker_.reset();
  input_device_settings_controller_.reset();
  input_device_key_alias_manager_.reset();

  screen_orientation_controller_.reset();
  screen_layout_observer_.reset();

  // Destroy the virtual keyboard controller before the tablet mode controller
  // since the latters destructor triggers events that the former is listening
  // to but no longer cares about.
  keyboard_controller_->DestroyVirtualKeyboard();

  // Depends on |tablet_mode_controller_|.
  window_restore_controller_.reset();
  shelf_controller_->Shutdown();
  shelf_config_->Shutdown();

  // Depends on `app_list_controller_` and `tablet_mode_controller_`.
  app_list_feature_usage_metrics_.reset();

  // Destroy |app_list_controller_| earlier than |tablet_mode_controller_| since
  // the former may use the latter before destruction.
  app_list_controller_.reset();

  // Accelerometer file reader stops listening to tablet mode controller.
  AccelerometerReader::GetInstance()->StopListenToTabletModeController();

  if (features::AreGlanceablesEnabled()) {
    // Close all glanceables so that all widgets are destroyed.
    glanceables_controller_->DestroyUi();
  }

  // Destroy |ambient_controller_| before |assistant_controller_|.
  ambient_controller_.reset();

  // Destroy |assistant_controller_| earlier than |tablet_mode_controller_| so
  // that the former will destroy the Assistant view hierarchy which has a
  // dependency on the latter.
  assistant_controller_.reset();

  // Because this function will call |TabletModeController::RemoveObserver|, do
  // it before destroying |tablet_mode_controller_|.
  accessibility_controller_->Shutdown();

  // Must be destructed before human_presence_orientation_controller_.
  power_prefs_.reset();

  // Must be destructed before the tablet mode and message center controllers,
  // both of which these rely on.
  snooping_protection_controller_.reset();
  human_presence_orientation_controller_.reset();

  snap_group_controller_.reset();

  // Shutdown tablet mode controller early on since it has some observers which
  // need to be removed. It will be destroyed later after all windows are closed
  // since it might be accessed during this process.
  tablet_mode_controller_->Shutdown();

  // Shutdown the clipboard history controller to clean up the child windows and
  // widgets that may be animating out.
  clipboard_history_controller_->Shutdown();

  toast_manager_.reset();

  // Accesses root window containers.
  logout_confirmation_controller_.reset();

  adaptive_charging_controller_.reset();

  // Drag-and-drop must be canceled prior to close all windows.
  drag_drop_controller_.reset();

  // Controllers who have WindowObserver added must be deleted
  // before |window_tree_host_manager_| is deleted.
  persistent_window_controller_.reset();

  display_highlight_controller_.reset();

  // VideoActivityNotifier must be deleted before |video_detector_| is
  // deleted because it's observing video activity through
  // VideoDetector::Observer interface.
  video_activity_notifier_.reset();
  video_detector_.reset();
  color_enhancement_controller_.reset();

  shadow_controller_.reset();
  resize_shadow_controller_.reset();
  raster_scale_controller_.reset();

  // Has to happen before ~MruWindowTracker.
  window_cycle_controller_.reset();
  overview_controller_.reset();

  game_dashboard_controller_.reset();

  // This must be destroyed before deleting all the windows below in
  // `CloseAllRootWindowChildWindows()`, since shutting down the session will
  // need to access those windows and it will be a UAF.
  // https://crbug.com/1350711.
  capture_mode_controller_.reset();

  // This must be called before deleting all the windows below in
  // `CloseAllRootWindowChildWindows()` since host_windows(which gets destroyed)
  // are needed for proper deletion of RoundedDisplayProviders.
  window_tree_host_manager_->ShutdownRoundedDisplays();

  // Close all widgets (including the shelf) and destroy all window containers.
  CloseAllRootWindowChildWindows();

  // Glanceables has a dependency on `tablet_mode_controller_`. Should be
  // destroyed first to remove the tablet mode observer.
  glanceables_controller_.reset();
  glanceables_v2_controller_.reset();

  multitask_menu_nudge_delegate_.reset();
  tablet_mode_controller_.reset();
  login_screen_controller_.reset();
  system_notification_controller_.reset();
  // Should be destroyed after Shelf and |system_notification_controller_|.
  system_tray_model_.reset();
  system_sounds_delegate_.reset();

  // MultiDisplayMetricsController has a dependency on `mru_window_tracker_`.
  multi_display_metrics_controller_.reset();

  // MruWindowTracker must be destroyed after all windows have been deleted to
  // avoid a possible crash when Shell is destroyed from a non-normal shutdown
  // path. (crbug.com/485438).
  mru_window_tracker_.reset();

  // These need a valid Shell instance to clean up properly, so explicitly
  // delete them before invalidating the instance.
  // Alphabetical. TODO(oshima): sort.
  autoclick_controller_.reset();
  fullscreen_magnifier_controller_.reset();
  tooltip_controller_.reset();
  event_client_.reset();
  toplevel_window_event_handler_.reset();
  visibility_controller_.reset();

  tray_action_.reset();

  power_button_controller_.reset();
  lock_state_controller_.reset();
  backlights_forced_off_setter_.reset();

  float_controller_.reset();
  screen_pinning_controller_.reset();

  multidevice_notification_presenter_.reset();
  resolution_notification_controller_.reset();
  mouse_cursor_filter_.reset();
  modality_filter_.reset();

  touch_transformer_controller_.reset();
  key_accessibility_enabler_.reset();

  display_speaker_controller_.reset();
  screen_switch_check_controller_.reset();

  ScreenAsh::CreateScreenForShutdown();
  display_configuration_controller_.reset();

  // Needs to be destructed before `ime_controler_`.
  keyboard_backlight_color_controller_.reset();
  rgb_keyboard_manager_.reset();

  ash_color_provider_.reset();

  // Depends on `dark_light_mode_controller_` and `wallpaper_controller_` so it
  // should be destroyed first.
  color_palette_controller_.reset();

  // Depends on `geolocation_controller_` and `wallpaper_controller_`, so it
  // must be destructed before the geolocation controller and wallpaper
  // controller.
  dark_light_mode_controller_.reset();

  // These members access Shell in their destructors.
  wallpaper_controller_.reset();
  accessibility_controller_.reset();
  accessibility_delegate_.reset();
  accessibility_focus_ring_controller_.reset();
  policy_recommendation_restorer_.reset();
  ime_controller_.reset();
  back_gesture_event_handler_.reset();

  // Balances the Install() in Initialize().
  views::FocusManagerFactory::Install(nullptr);

  // ShelfWindowWatcher has window observers and a pointer to the shelf model.
  shelf_window_watcher_.reset();

  // Removes itself as an observer of |pref_service_|.
  shelf_controller_.reset();

  // NightLightControllerImpl depends on the PrefService, the window tree host
  // manager, and `geolocation_controller_`, so it must be destructed before
  // them. crbug.com/724231.
  night_light_controller_ = nullptr;
  // Similarly for DockedMagnifierController.
  docked_magnifier_controller_ = nullptr;
  // Similarly for PrivacyScreenController.
  privacy_screen_controller_ = nullptr;
  // Similarly for AutozoomControllerImpl
  autozoom_controller_ = nullptr;

  geolocation_controller_.reset();

  // NearbyShareDelegateImpl must be destroyed before SessionController and
  // NearbyShareControllerImpl.
  nearby_share_delegate_.reset();
  nearby_share_controller_.reset();

  // Stop observing window activation changes before closing all windows.
  focus_controller_->RemoveObserver(this);

  // Depends on shelf owned by RootWindowController so destroy this before the
  // |window_tree_host_manager_|.
  clipboard_history_controller_.reset();

  // This also deletes all RootWindows. Note that we invoke Shutdown() on
  // WindowTreeHostManager before resetting |window_tree_host_manager_|, since
  // destruction of its owned RootWindowControllers relies on the value.
  window_tree_host_manager_->Shutdown();

  // Depends on |focus_controller_|, so must be destroyed before.
  window_tree_host_manager_.reset();

  // The desks controller is destroyed after the window tree host manager and
  // before the focus controller. At this point it is guaranteed that querying
  // the active desk is no longer needed.
  desks_controller_.reset();

  tab_cluster_ui_controller_.reset();

  focus_rules_ = nullptr;
  focus_controller_.reset();
  screen_position_controller_.reset();

  display_color_manager_.reset();
  projecting_observer_.reset();

  projector_controller_.reset();

  partial_magnifier_controller_.reset();

  touch_selection_magnifier_runner_ash_.reset();

  laser_pointer_controller_.reset();

  if (display_change_observer_) {
    display_manager_->configurator()->RemoveObserver(
        display_change_observer_.get());
  }
  if (display_error_observer_) {
    display_manager_->configurator()->RemoveObserver(
        display_error_observer_.get());
  }
  display_change_observer_.reset();
  display_shutdown_observer_.reset();

  keyboard_controller_.reset();

  PowerStatus::Shutdown();
  // Depends on SessionController.
  power_event_observer_.reset();

  session_controller_->RemoveObserver(this);
  // TouchDevicesController depends on the PrefService and must be destructed
  // before it.
  touch_devices_controller_ = nullptr;
  // DetachableBaseNotificationController depends on DetachableBaseHandler, and
  // has to be destructed before it.
  detachable_base_notification_controller_.reset();
  // DetachableBaseHandler depends on the PrefService and must be destructed
  // before it.
  detachable_base_handler_.reset();

  diagnostics_log_controller_.reset();

  firmware_update_notification_controller_.reset();

  firmware_update_manager_.reset();

  pcie_peripheral_notification_controller_.reset();

  usb_peripheral_notification_controller_.reset();

  keyboard_capability_.reset();

  message_center_ash_impl_.reset();

  // Destroys the MessageCenter singleton, so must happen late.
  message_center_controller_.reset();

  // `HoldingSpaceController` observes `SessionController` and must be
  // destructed before it.
  holding_space_controller_.reset();

  // `CalendarController` observes `SessionController` and must be destructed
  // before it.
  calendar_controller_.reset();

  camera_effects_controller_.reset();

  audio_effects_controller_.reset();

  shell_delegate_.reset();

  multi_capture_service_client_.reset();

  // Observes `SessionController` and must be destroyed before it.
  federated_service_controller_.reset();

  UsbguardClient::Shutdown();

  // Must be shut down after detachable_base_handler_.
  HammerdClient::Shutdown();

  if (FwupdClient::Get()) {
    FwupdClient::Shutdown();
  }

  for (auto& observer : shell_observers_) {
    observer.OnShellDestroyed();
  }

  DCHECK(instance_ == this);
  instance_ = nullptr;
}

void Shell::Init(
    ui::ContextFactory* context_factory,
    PrefService* local_state,
    std::unique_ptr<keyboard::KeyboardUIFactory> keyboard_ui_factory,
    scoped_refptr<dbus::Bus> dbus_bus) {
  login_unlock_throughput_recorder_ =
      std::make_unique<LoginUnlockThroughputRecorder>();

  // Required by DetachableBaseHandler.
  chromeos::InitializeDBusClient<HammerdClient>(dbus_bus.get());

  chromeos::InitializeDBusClient<UsbguardClient>(dbus_bus.get());

  local_state_ = local_state;

  // This creates the MessageCenter object which is used by some other objects
  // initialized here, so it needs to come early.
  message_center_controller_ = std::make_unique<MessageCenterController>();

  message_center_ash_impl_ = std::make_unique<MessageCenterAshImpl>();

  // Initialized early since it is used by some other objects.
  keyboard_capability_ = std::make_unique<ui::KeyboardCapability>(
      std::make_unique<KeyboardCapabilityDelegateImpl>());

  // These controllers call Shell::Get() in their constructors, so they cannot
  // be in the member initialization list.
  touch_devices_controller_ = std::make_unique<TouchDevicesController>();
  detachable_base_handler_ =
      std::make_unique<DetachableBaseHandler>(local_state_);
  detachable_base_notification_controller_ =
      std::make_unique<DetachableBaseNotificationController>(
          detachable_base_handler_.get());
  display_speaker_controller_ = std::make_unique<DisplaySpeakerController>();
  policy_recommendation_restorer_ =
      std::make_unique<PolicyRecommendationRestorer>();
  screen_switch_check_controller_ =
      std::make_unique<ScreenSwitchCheckController>();
  multidevice_notification_presenter_ =
      std::make_unique<MultiDeviceNotificationPresenter>(
          message_center::MessageCenter::Get());
  media_controller_ = std::make_unique<MediaControllerImpl>();
  media_notification_provider_ =
      shell_delegate_->CreateMediaNotificationProvider();

  tablet_mode_controller_ = std::make_unique<TabletModeController>();

  if (features::IsRgbKeyboardEnabled()) {
    rgb_keyboard_manager_ =
        std::make_unique<RgbKeyboardManager>(ime_controller_.get());
  }

  // Observes the tablet mode controller if any hps feature is enabled.
  if (features::IsSnoopingProtectionEnabled() ||
      features::IsQuickDimEnabled()) {
    human_presence_orientation_controller_ =
        std::make_unique<HumanPresenceOrientationController>();
  }

  // Construct SnoopingProtectionController, must be constructed after
  // HumanPresenceOrientationController.
  if (features::IsSnoopingProtectionEnabled()) {
    snooping_protection_controller_ =
        std::make_unique<SnoopingProtectionController>();
  }

  // Manages lifetime of DiagnosticApp logs.
  if (features::IsLogControllerForDiagnosticsAppEnabled()) {
    diagnostics_log_controller_ =
        std::make_unique<diagnostics::DiagnosticsLogController>();
  }

  pcie_peripheral_notification_controller_ =
      std::make_unique<PciePeripheralNotificationController>(
          message_center::MessageCenter::Get());

  usb_peripheral_notification_controller_ =
      std::make_unique<UsbPeripheralNotificationController>(
          message_center::MessageCenter::Get());

  accessibility_focus_ring_controller_ =
      std::make_unique<AccessibilityFocusRingControllerImpl>();
  accessibility_delegate_.reset(shell_delegate_->CreateAccessibilityDelegate());
  accessibility_controller_ = std::make_unique<AccessibilityControllerImpl>();
  toast_manager_ = std::make_unique<ToastManagerImpl>();

  peripheral_battery_listener_ = std::make_unique<PeripheralBatteryListener>();

  peripheral_battery_notifier_ = std::make_unique<PeripheralBatteryNotifier>(
      peripheral_battery_listener_.get());
  power_event_observer_ = std::make_unique<PowerEventObserver>();
  window_cycle_controller_ = std::make_unique<WindowCycleController>();

  capture_mode_controller_ = std::make_unique<CaptureModeController>(
      shell_delegate_->CreateCaptureModeDelegate());

  if (features::IsGameDashboardEnabled()) {
    game_dashboard_controller_ = std::make_unique<GameDashboardController>(
        shell_delegate_->CreateGameDashboardDelegate());
  }

  // Accelerometer file reader starts listening to tablet mode controller.
  AccelerometerReader::GetInstance()->StartListenToTabletModeController();

  // Install the custom factory early on so that views::FocusManagers for Tray,
  // Shelf, and WallPaper could be created by the factory.
  views::FocusManagerFactory::Install(new AshFocusManagerFactory);

  wallpaper_controller_ = WallpaperControllerImpl::Create(local_state_);

  if (features::IsRgbKeyboardEnabled()) {
    // Initialized after |rgb_keyboard_manager_| to observe the state of rgb
    // keyboard and |wallpaper_controller_| because we will need to observe when
    // the extracted wallpaper color changes.
    keyboard_backlight_color_controller_ =
        std::make_unique<KeyboardBacklightColorController>(local_state_);
  }

  native_cursor_manager_ = new NativeCursorManagerAsh;
  cursor_manager_ = std::make_unique<CursorManager>(
      base::WrapUnique(native_cursor_manager_.get()));

  InitializeDisplayManager();

  // RefreshFontParams depends on display prefs.
  display_manager_->RefreshFontParams();

  // This will initialize aura::Env which requires |display_manager_| to
  // be initialized first.
  aura::Env* env = aura::Env::GetInstance();
  if (context_factory) {
    env->set_context_factory(context_factory);
  }

  ash_color_provider_ = std::make_unique<AshColorProvider>();
  ui::ColorProviderManager::Get().AppendColorProviderInitializer(
      base::BindRepeating(AddCrosStylesColorMixer));
  ui::ColorProviderManager::Get().AppendColorProviderInitializer(
      base::BindRepeating(AddAshColorMixer));

  // Geolocation controller needs to be created before any `ScheduledFeature`
  // subclasses such as night light and dark mode controllers because
  // `ScheduledFeature` ctor will access `geolocation_controller_` from
  // `Shell`.
  geolocation_controller_ = std::make_unique<GeolocationController>(
      shell_delegate_->GetGeolocationUrlLoaderFactory());

  // Night Light depends on the display manager, the display color manager,
  // aura::Env, and geolocation controller, so initialize it after all have
  // been initialized.
  night_light_controller_ = std::make_unique<NightLightControllerImpl>();

  dark_light_mode_controller_ = std::make_unique<DarkLightModeControllerImpl>();

  color_palette_controller_ = ColorPaletteController::Create(
      dark_light_mode_controller_.get(), wallpaper_controller_.get());

  // Privacy Screen depends on the display manager, so initialize it after
  // display manager was properly initialized.
  privacy_screen_controller_ = std::make_unique<PrivacyScreenController>();

  if (media::ShouldEnableAutoFraming()) {
    autozoom_controller_ = std::make_unique<AutozoomControllerImpl>();
  }

  // Fast Pair depends on the display manager, so initialize it after
  // display manager was properly initialized.
  if (base::FeatureList::IsEnabled(features::kFastPair)) {
    quick_pair_mediator_ = quick_pair::Mediator::Factory::Create();
  }

  // The WindowModalityController needs to be at the front of the input event
  // pretarget handler list to ensure that it processes input events when modal
  // windows are active.
  window_modality_controller_ =
      std::make_unique<::wm::WindowModalityController>(this, env);

  input_device_key_alias_manager_ =
      std::make_unique<InputDeviceKeyAliasManager>();

  // The `InputDeviceSettingsController` is a dependency of the following so it
  // must be initialized first:
  //  - `EventRewriterController`
  //  - `InputDeviceTracker`
  //  - `KeyboardModifierMetricsRecorder`
  //  - `InputDeviceSettingsDispatcher`
  input_device_settings_controller_ =
      std::make_unique<InputDeviceSettingsControllerImpl>(local_state_);
  input_device_tracker_ = std::make_unique<InputDeviceTracker>();
  input_device_settings_dispatcher_ =
      std::make_unique<InputDeviceSettingsDispatcher>(
          ui::OzonePlatform::GetInstance()->GetInputController());
  keyboard_modifier_metrics_recorder_ =
      std::make_unique<KeyboardModifierMetricsRecorder>();
  event_rewriter_controller_ = std::make_unique<EventRewriterControllerImpl>();

  env_filter_ = std::make_unique<::wm::CompoundEventFilter>();
  AddPreTargetHandler(env_filter_.get());

  if (features::IsSnapGroupEnabled()) {
    snap_group_controller_ = std::make_unique<SnapGroupController>();
  }

  // FocusController takes ownership of AshFocusRules.
  focus_rules_ = new AshFocusRules();
  focus_controller_ = std::make_unique<::wm::FocusController>(focus_rules_);
  focus_controller_->AddObserver(this);

  overview_controller_ = std::make_unique<OverviewController>();

  screen_position_controller_ = std::make_unique<ScreenPositionController>();

  frame_throttling_controller_ = std::make_unique<FrameThrottlingController>(
      context_factory->GetHostFrameSinkManager());

  if (features::IsTabClusterUIEnabled()) {
    tab_cluster_ui_controller_ = std::make_unique<TabClusterUIController>();
  }

  window_tree_host_manager_->Start();
  AshWindowTreeHostInitParams ash_init_params;
  window_tree_host_manager_->CreatePrimaryHost(ash_init_params);

  // Create the desks controller right after the window tree host manager is
  // started, and before anything else is created, including the initialization
  // of the hosts and the root window controllers. Many things may need to query
  // the active desk, even at this early stage. For this the controller must be
  // present at all times. The desks controller also depends on the focus
  // controller.
  desks_controller_ = std::make_unique<DesksController>();
  saved_desk_delegate_ = shell_delegate_->CreateSavedDeskDelegate();
  // Initialized here since it depends on desks.
  if (base::FeatureList::IsEnabled(features::kAppLaunchAutomation)) {
    saved_desk_controller_ = std::make_unique<SavedDeskController>();
  }

  Shell::SetRootWindowForNewWindows(GetPrimaryRootWindow());

  resolution_notification_controller_ =
      std::make_unique<ResolutionNotificationController>();

  cursor_manager_->SetDisplay(
      display::Screen::GetScreen()->GetPrimaryDisplay());

  // Must be initialized after InputMethodManager.
  accelerator_keycode_lookup_cache_ =
      std::make_unique<AcceleratorKeycodeLookupCache>();
  ash_accelerator_configuration_ =
      std::make_unique<AshAcceleratorConfiguration>();
  ash_accelerator_configuration_->Initialize();
  accelerator_controller_ = std::make_unique<AcceleratorControllerImpl>(
      ash_accelerator_configuration_.get());

  clipboard_history_controller_ =
      std::make_unique<ClipboardHistoryControllerImpl>();

  // `HoldingSpaceController` must be instantiated before the shelf.
  holding_space_controller_ = std::make_unique<HoldingSpaceController>();

  calendar_controller_ = std::make_unique<CalendarController>();

  if (features::IsVideoConferenceEnabled()) {
    camera_effects_controller_ = std::make_unique<CameraEffectsController>();
    audio_effects_controller_ = std::make_unique<AudioEffectsController>();
  }

  shelf_config_ = std::make_unique<ShelfConfig>();
  shelf_controller_ = std::make_unique<ShelfController>();

  shell_tab_handler_ = std::make_unique<ShellTabHandler>(this);
  AddPreTargetHandler(shell_tab_handler_.get());
  magnifier_key_scroll_handler_ = MagnifierKeyScroller::CreateHandler();
  AddPreTargetHandler(magnifier_key_scroll_handler_.get());
  speech_feedback_handler_ = SpokenFeedbackToggler::CreateHandler();
  AddPreTargetHandler(speech_feedback_handler_.get());

  // The order in which event filters are added is significant.

  // ui::UserActivityDetector passes events to observers, so let them get
  // rewritten first.
  user_activity_detector_ = std::make_unique<ui::UserActivityDetector>();

  control_v_histogram_recorder_ = std::make_unique<ControlVHistogramRecorder>();
  AddPreTargetHandler(control_v_histogram_recorder_.get(),
                      ui::EventTarget::Priority::kAccessibility);

  // AcceleratorTracker should be placed before AcceleratorFilter to make sure
  // the accelerators won't be filtered out before getting AcceleratorTracker.
  accelerator_tracker_ = std::make_unique<AcceleratorTracker>(
      base::make_span(kAcceleratorTrackerList, kAcceleratorTrackerListLength));
  AddPreTargetHandler(accelerator_tracker_.get());

  accelerator_filter_ = std::make_unique<::wm::AcceleratorFilter>(
      std::make_unique<PreTargetAcceleratorHandler>());
  AddPreTargetHandler(accelerator_filter_.get());

  event_transformation_handler_ =
      std::make_unique<EventTransformationHandler>();
  AddPreTargetHandler(event_transformation_handler_.get());

  back_gesture_event_handler_ = std::make_unique<BackGestureEventHandler>();
  AddPreTargetHandler(back_gesture_event_handler_.get());

  toplevel_window_event_handler_ =
      std::make_unique<ToplevelWindowEventHandler>();

  system_gesture_filter_ = std::make_unique<SystemGestureEventFilter>();
  AddPreTargetHandler(system_gesture_filter_.get());

  sticky_keys_controller_ = std::make_unique<StickyKeysController>();
  screen_pinning_controller_ = std::make_unique<ScreenPinningController>();

  power_prefs_ = std::make_unique<PowerPrefs>(
      chromeos::PowerPolicyController::Get(),
      chromeos::PowerManagerClient::Get(), local_state_);

  backlights_forced_off_setter_ = std::make_unique<BacklightsForcedOffSetter>();

  tray_action_ =
      std::make_unique<TrayAction>(backlights_forced_off_setter_.get());

  lock_state_controller_ = std::make_unique<LockStateController>(
      shutdown_controller_.get(), local_state_);
  power_button_controller_ = std::make_unique<PowerButtonController>(
      backlights_forced_off_setter_.get());
  // Pass the initial display state to PowerButtonController.
  power_button_controller_->OnDisplayModeChanged(
      display_configurator()->cached_displays());

  drag_drop_controller_ = std::make_unique<DragDropController>();

  mouse_cursor_filter_ = std::make_unique<MouseCursorEventFilter>();
  AddAccessibilityEventHandler(
      mouse_cursor_filter_.get(),
      AccessibilityEventHandlerManager::HandlerType::kCursor);

  if (features::IsAdaptiveChargingEnabled()) {
    adaptive_charging_controller_ =
        std::make_unique<AdaptiveChargingController>();
  }

  // Create Controllers that may need root window.
  // TODO(oshima): Move as many controllers before creating
  // RootWindowController as possible.
  visibility_controller_ = std::make_unique<AshVisibilityController>();

  laser_pointer_controller_ = std::make_unique<LaserPointerController>();
  partial_magnifier_controller_ =
      std::make_unique<PartialMagnifierController>();
  if (::features::IsTouchTextEditingRedesignEnabled()) {
    touch_selection_magnifier_runner_ash_ =
        std::make_unique<TouchSelectionMagnifierRunnerAsh>();
  }

  fullscreen_magnifier_controller_ =
      std::make_unique<FullscreenMagnifierController>();
  mru_window_tracker_ = std::make_unique<MruWindowTracker>();
  assistant_controller_ = std::make_unique<AssistantControllerImpl>();

  // MultiDisplayMetricsController has a dependency on `mru_window_tracker_`.
  multi_display_metrics_controller_ =
      std::make_unique<MultiDisplayMetricsController>();

  mojo::PendingRemote<device::mojom::Fingerprint> ambient_fingerprint;
  shell_delegate_->BindFingerprint(
      ambient_fingerprint.InitWithNewPipeAndPassReceiver());
  ambient_controller_ =
      std::make_unique<AmbientController>(std::move(ambient_fingerprint));

  mojo::PendingRemote<video_capture::mojom::MultiCaptureService>
      multi_capture_service;
  shell_delegate_->BindMultiCaptureService(
      multi_capture_service.InitWithNewPipeAndPassReceiver());
  multi_capture_service_client_ = std::make_unique<MultiCaptureServiceClient>(
      std::move(multi_capture_service));

  // |tablet_mode_controller_| |mru_window_tracker_|, and
  // |assistant_controller_| are put before |app_list_controller_| as they are
  // used in its constructor.
  app_list_controller_ = std::make_unique<AppListControllerImpl>();

  autoclick_controller_ = std::make_unique<AutoclickController>();

  color_enhancement_controller_ =
      std::make_unique<ColorEnhancementController>();

  security_curtain_controller_ =
      std::make_unique<curtain::SecurityCurtainControllerImpl>(this);

  docked_magnifier_controller_ = std::make_unique<DockedMagnifierController>();

  video_detector_ = std::make_unique<VideoDetector>();

  tooltip_controller_ = std::make_unique<views::corewm::TooltipController>(
      std::make_unique<views::corewm::TooltipAura>(
          base::BindRepeating(&StyleUtil::CreateAshStyleTooltipView)),
      activation_client());
  AddPreTargetHandler(tooltip_controller_.get());

  modality_filter_ = std::make_unique<SystemModalContainerEventFilter>(this);
  AddPreTargetHandler(modality_filter_.get());

  event_client_ = std::make_unique<EventClientImpl>();

  resize_shadow_controller_ = std::make_unique<ResizeShadowController>();
  raster_scale_controller_ = std::make_unique<RasterScaleController>();
  shadow_controller_ = std::make_unique<::wm::ShadowController>(
      focus_controller_.get(), std::make_unique<WmShadowControllerDelegate>(),
      env);

  logout_confirmation_controller_ =
      std::make_unique<LogoutConfirmationController>();

  // Create AshTouchTransformController before
  // WindowTreeHostManager::InitDisplays()
  // since AshTouchTransformController listens on
  // WindowTreeHostManager::Observer::OnDisplaysInitialized().
  touch_transformer_controller_ = std::make_unique<AshTouchTransformController>(
      display_manager_.get(),
      std::make_unique<display::DefaultTouchTransformSetter>());

  // |system_tray_model_| should be available before
  // |system_notification_controller_| is initialized and Shelf is created by
  // WindowTreeHostManager::InitHosts.
  system_tray_model_ = std::make_unique<SystemTrayModel>();

  // The |shelf_config_| needs |app_list_controller_| and |system_tray_model_|
  // to initialize itself.
  shelf_config_->Init();

  // The `shelf_controller_` needs `app_list_controller_` to initialize
  // launcher_nudge_controller_.
  shelf_controller_->Init();

  nearby_share_controller_ = std::make_unique<NearbyShareControllerImpl>();
  nearby_share_delegate_ = shell_delegate_->CreateNearbyShareDelegate(
      nearby_share_controller_.get());

  // System sounds delegate should be initialized before
  // `SystemNotificationController` is created, because
  // `SystemNotificationController` ctor will creat an instance of
  // `PowerSoundsController`, which will access and play the initialized sounds.
  if (features::AreSystemSoundsEnabled()) {
    system_sounds_delegate_ = shell_delegate_->CreateSystemSoundsDelegate();
    system_sounds_delegate_->Init();
  }

  system_notification_controller_ =
      std::make_unique<SystemNotificationController>();

  if (features::IsCrosPrivacyHubEnabled()) {
    // One of the subcontrollers accesses the SystemNotificationController.
    privacy_hub_controller_ = std::make_unique<PrivacyHubController>();
  } else if (features::IsMicMuteNotificationsEnabled()) {
    // TODO(b/264388354) Until PrivacyHub is enabled for all keep this around
    // for the already existing microphone notifications to continue working.
    microphone_privacy_switch_controller_ =
        std::make_unique<MicrophonePrivacySwitchController>();
  }

  // WmModeController should be created before initializing the window tree
  // hosts, since the latter will initialize the shelf on each display, which
  // hosts the WM mode tray button.
  if (features::IsWmModeEnabled()) {
    wm_mode_controller_ = std::make_unique<WmModeController>();
  }

  window_tree_host_manager_->InitHosts();

  // Create virtual keyboard after WindowTreeHostManager::InitHosts() since
  // it may enable the virtual keyboard immediately, which requires a
  // WindowTreeHostManager to host the keyboard window.
  keyboard_controller_->CreateVirtualKeyboard(std::move(keyboard_ui_factory));

  // Create window restore controller after `WindowTreeHostManager::InitHosts()`
  // since it may need to add observers to root windows.
  window_restore_controller_ = std::make_unique<WindowRestoreController>();

  static_cast<CursorManager*>(cursor_manager_.get())->Init();

  mojo::PendingRemote<device::mojom::Fingerprint> fingerprint;
  shell_delegate_->BindFingerprint(
      fingerprint.InitWithNewPipeAndPassReceiver());
  user_activity_notifier_ =
      std::make_unique<ui::UserActivityPowerManagerNotifier>(
          user_activity_detector_.get(), std::move(fingerprint));
  video_activity_notifier_ =
      std::make_unique<VideoActivityNotifier>(video_detector_.get());
  bluetooth_state_cache_ = std::make_unique<BluetoothStateCache>();
  bluetooth_device_status_ui_handler_ =
      std::make_unique<BluetoothDeviceStatusUiHandler>();
  bluetooth_notification_controller_ =
      std::make_unique<BluetoothNotificationController>(
          message_center::MessageCenter::Get());
  screen_orientation_controller_ =
      std::make_unique<ScreenOrientationController>();

  cros_display_config_ = std::make_unique<CrosDisplayConfig>();

  screen_layout_observer_ = std::make_unique<ScreenLayoutObserver>();
  sms_observer_ = std::make_unique<SmsObserver>();
  snap_controller_ = std::make_unique<SnapControllerImpl>();
  key_accessibility_enabler_ = std::make_unique<KeyAccessibilityEnabler>();

  // The compositor thread and main message loop have to be running in
  // order to create mirror window. Run it after the main message loop
  // is started.
  display_manager_->CreateMirrorWindowAsyncIfAny();

  // TODO(1091497): Consider combining DisplayHighlightController and
  // DisplayAlignmentController.
  display_highlight_controller_ =
      std::make_unique<DisplayHighlightController>();

  if (features::IsDisplayAlignmentAssistanceEnabled()) {
    display_alignment_controller_ =
        std::make_unique<DisplayAlignmentController>();
  }

  if (features::AreGlanceablesEnabled()) {
    glanceables_controller_ = std::make_unique<GlanceablesController>();
    glanceables_controller_->Init(shell_delegate_->CreateGlanceablesDelegate(
        glanceables_controller_.get()));
  }

  if (features::AreGlanceablesV2Enabled()) {
    glanceables_v2_controller_ = std::make_unique<GlanceablesV2Controller>();
  }

  if (features::IsProjectorEnabled()) {
    projector_controller_ = std::make_unique<ProjectorControllerImpl>();
  }

  if (chromeos::wm::features::IsWindowLayoutMenuEnabled()) {
    float_controller_ = std::make_unique<FloatController>();
    multitask_menu_nudge_delegate_ =
        std::make_unique<MultitaskMenuNudgeDelegateAsh>();
  }

  if (features::IsFederatedServiceEnabled()) {
    federated_service_controller_ =
        std::make_unique<federated::FederatedServiceControllerImpl>();
  }

  if (features::IsUserEducationEnabled()) {
    user_education_controller_ = std::make_unique<UserEducationController>(
        shell_delegate_->CreateUserEducationDelegate());
  }

  // Injects the factory which fulfills the implementation of the text context
  // menu exclusive to CrOS.
  views::ViewsTextServicesContextMenuChromeos::SetImplFactory(
      base::BindRepeating(
          [](ui::SimpleMenuModel* menu_model, views::Textfield* textfield)
              -> std::unique_ptr<views::ViewsTextServicesContextMenu> {
            return std::make_unique<ViewsTextServicesContextMenuAsh>(menu_model,
                                                                     textfield);
          }));

  for (auto& observer : shell_observers_) {
    observer.OnShellInitialized();
  }

  user_metrics_recorder_->OnShellInitialized();

  occlusion_tracker_pauser_ = std::make_unique<OcclusionTrackerPauser>();

  // Initialize the D-Bus bus and services for ash.
  dbus_bus_ = dbus_bus;
  ash_dbus_services_ = std::make_unique<AshDBusServices>(dbus_bus.get());
}

void Shell::InitializeDisplayManager() {
  display_manager_->InitConfigurator(
      ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate());
  display_configuration_controller_ =
      std::make_unique<DisplayConfigurationController>(
          display_manager_.get(), window_tree_host_manager_.get());
  display_configuration_observer_ =
      std::make_unique<DisplayConfigurationObserver>();

  persistent_window_controller_ =
      std::make_unique<PersistentWindowController>();

  projecting_observer_ =
      std::make_unique<ProjectingObserver>(display_manager_->configurator());

  if (base::FeatureList::IsEnabled(features::kSeamlessRefreshRateSwitching)) {
    refresh_rate_throttle_controller_ =
        std::make_unique<RefreshRateThrottleController>(
            display_manager_->configurator(), PowerStatus::Get());
  }

  display_prefs_ = std::make_unique<DisplayPrefs>(local_state_);

  bool display_initialized = display_manager_->InitFromCommandLine();

  if (!display_initialized) {
    if (base::SysInfo::IsRunningOnChromeOS()) {
      display_change_observer_ =
          std::make_unique<display::DisplayChangeObserver>(
              display_manager_.get());

      display_error_observer_ = std::make_unique<DisplayErrorObserver>();
      display_shutdown_observer_ = std::make_unique<DisplayShutdownObserver>(
          display_manager_->configurator());

      display_manager_->ForceInitialConfigureWithObservers(
          display_change_observer_.get(), display_error_observer_.get());
      display_initialized = true;
    }
  }

  display_color_manager_ =
      std::make_unique<DisplayColorManager>(display_manager_->configurator());

  if (!display_initialized) {
    display_manager_->InitDefaultDisplay();
  }
}

void Shell::InitRootWindow(aura::Window* root_window) {
  DCHECK(focus_controller_);
  DCHECK(visibility_controller_.get());

  aura::client::SetFocusClient(root_window, focus_controller_.get());
  ::wm::SetActivationClient(root_window, focus_controller_.get());
  root_window->AddPreTargetHandler(focus_controller_.get());
  aura::client::SetVisibilityClient(root_window, visibility_controller_.get());
  aura::client::SetDragDropClient(root_window, drag_drop_controller_.get());
  aura::client::SetScreenPositionClient(root_window,
                                        screen_position_controller_.get());
  aura::client::SetCursorClient(root_window, cursor_manager_.get());
  ::wm::SetTooltipClient(root_window, tooltip_controller_.get());
  aura::client::SetEventClient(root_window, event_client_.get());

  ::wm::SetWindowMoveClient(root_window, toplevel_window_event_handler_.get());
  root_window->AddPreTargetHandler(toplevel_window_event_handler_.get());
  root_window->AddPostTargetHandler(toplevel_window_event_handler_.get());
}

void Shell::CloseAllRootWindowChildWindows() {
  for (aura::Window* root : GetAllRootWindows()) {
    RootWindowController* controller = RootWindowController::ForWindow(root);
    if (controller) {
      controller->CloseChildWindows();
    } else {
      while (!root->children().empty()) {
        aura::Window* child = root->children()[0];
        delete child;
      }
    }
  }
}

bool Shell::CanWindowReceiveEvents(aura::Window* window) {
  RootWindowControllerList controllers = GetAllRootWindowControllers();
  for (RootWindowController* controller : controllers) {
    if (controller->CanWindowReceiveEvents(window)) {
      return true;
    }
  }
  return false;
}

////////////////////////////////////////////////////////////////////////////////
// Shell, ui::EventTarget overrides:

bool Shell::CanAcceptEvent(const ui::Event& event) {
  return true;
}

ui::EventTarget* Shell::GetParentTarget() {
  return aura::Env::GetInstance();
}

std::unique_ptr<ui::EventTargetIterator> Shell::GetChildIterator() const {
  return nullptr;
}

ui::EventTargeter* Shell::GetEventTargeter() {
  NOTREACHED();
  return nullptr;
}

void Shell::OnWindowActivated(
    ::wm::ActivationChangeObserver::ActivationReason reason,
    aura::Window* gained_active,
    aura::Window* lost_active) {
  if (!gained_active) {
    return;
  }

  Shell::SetRootWindowForNewWindows(gained_active->GetRootWindow());
}

void Shell::OnFirstSessionStarted() {
  // Enable magnifier scroll keys as there may be no mouse cursor in kiosk mode.
  MagnifierKeyScroller::SetEnabled(session_controller_->IsRunningInAppMode());

  // Enable long press action to toggle spoken feedback with hotrod remote
  // which can't handle shortcuts.
  SpokenFeedbackToggler::SetEnabled(session_controller_->IsRunningInAppMode());

  // Reset user prefs related to contextual tooltips.
  if (switches::ContextualNudgesResetShownCount()) {
    contextual_tooltip::ClearPrefs();
  }

  // The launcher is not available before login, so start tracking usage after
  // the session starts.
  app_list_feature_usage_metrics_ =
      std::make_unique<AppListFeatureUsageMetrics>();
}

void Shell::OnSessionStateChanged(session_manager::SessionState state) {
  const bool is_session_active = state == session_manager::SessionState::ACTIVE;
  // Initialize the |shelf_window_watcher_| when a session becomes active.
  // Shelf itself is initialized in RootWindowController.
  if (is_session_active && !shelf_window_watcher_) {
    shelf_window_watcher_ =
        std::make_unique<ShelfWindowWatcher>(shelf_controller()->model());
  }

  // Initialize the fwupd (firmware updater) DBus client only when the user
  // session is active. Since the fwupd service is only relevant during an
  // active user session, this prevents a bug in which the service would start
  // up earlier than expected and causes a delay during boot.
  // See b/250002264 for more details.
  if (is_session_active && !FwupdClient::Get() &&
      !firmware_update_notification_controller_) {
    chromeos::InitializeDBusClient<FwupdClient>(dbus_bus_.get());
    firmware_update_manager_ = std::make_unique<FirmwareUpdateManager>();
    // The notification controller is registered as an observer before
    // requesting updates to allow a notification to be shown if a critical
    // firmware update is found.
    firmware_update_notification_controller_ =
        std::make_unique<FirmwareUpdateNotificationController>(
            message_center::MessageCenter::Get());
    firmware_update_manager_->RequestAllUpdates();
  }

  // Disable drag-and-drop during OOBE and GAIA login screens by only enabling
  // the controller when the session is active. https://crbug.com/464118
  drag_drop_controller_->set_enabled(is_session_active);
}

void Shell::OnLoginStatusChanged(LoginStatus login_status) {
  UpdateAfterLoginStatusChange(login_status);
}

void Shell::OnLockStateChanged(bool locked) {
#ifndef NDEBUG
  // Make sure that there is no system modal in Lock layer when unlocked.
  if (!locked) {
    aura::Window::Windows containers = GetContainersForAllRootWindows(
        kShellWindowId_LockSystemModalContainer, GetPrimaryRootWindow());
    for (aura::Window* container : containers) {
      DCHECK(container->children().empty());
    }
  }
#endif
}

}  // namespace ash