| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/crosapi/browser_action.h" |
| |
| #include <optional> |
| #include <string_view> |
| |
| #include "base/memory/weak_ptr.h" |
| #include "chrome/browser/ash/app_restore/full_restore_service.h" |
| #include "chrome/browser/ash/crosapi/crosapi_ash.h" |
| #include "chrome/browser/ash/crosapi/crosapi_manager.h" |
| #include "chrome/browser/ash/crosapi/desk_template_ash.h" |
| #include "chrome/browser/ash/floating_workspace/floating_workspace_util.h" |
| #include "chrome/browser/prefs/incognito_mode_prefs.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chromeos/components/kiosk/kiosk_utils.h" |
| #include "components/user_manager/user_manager.h" |
| |
| namespace crosapi { |
| |
| void BrowserAction::Cancel(crosapi::mojom::CreationResult reason) { |
| DCHECK_NE(reason, mojom::CreationResult::kSuccess); |
| } |
| |
| void BrowserAction::OnPerformed(BrowserManagerCallback on_performed, |
| mojom::CreationResult result) { |
| const bool retry = result == mojom::CreationResult::kBrowserShutdown; |
| std::move(on_performed).Run(retry); |
| } |
| |
| // No-op action, used to start the browser without opening a window. |
| class NoOpAction final : public BrowserAction { |
| public: |
| NoOpAction() : BrowserAction(true) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override {} |
| }; |
| |
| class NewWindowAction final : public BrowserAction { |
| public: |
| NewWindowAction(bool incognito, |
| bool should_trigger_session_restore, |
| int64_t target_display_id, |
| std::optional<uint64_t> profile_id = std::nullopt) |
| : BrowserAction(true), |
| incognito_(incognito), |
| should_trigger_session_restore_(should_trigger_session_restore), |
| target_display_id_(target_display_id), |
| profile_id_(profile_id), |
| weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kNewWindowMinVersion); |
| if (incognito_) { |
| Profile* profile = ProfileManager::GetPrimaryUserProfile(); |
| if (!profile || !IncognitoModePrefs::IsIncognitoAllowed(profile)) |
| return; |
| } |
| service.service->NewWindow(incognito_, should_trigger_session_restore_, |
| target_display_id_, profile_id_, |
| base::BindOnce(&NewWindowAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| const bool incognito_; |
| const bool should_trigger_session_restore_; |
| const int64_t target_display_id_; |
| const std::optional<uint64_t> profile_id_; |
| base::WeakPtrFactory<NewWindowAction> weak_ptr_factory_; |
| }; |
| |
| class NewWindowForDetachingTabAction final : public BrowserAction { |
| public: |
| NewWindowForDetachingTabAction(std::u16string_view tab_id_str, |
| std::u16string_view group_id_str, |
| NewWindowForDetachingTabCallback callback) |
| : BrowserAction(false), |
| tab_id_str_(tab_id_str), |
| group_id_str_(group_id_str), |
| callback_(std::move(callback)), |
| weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| mojom::BrowserService::kNewWindowForDetachingTabMinVersion); |
| service.service->NewWindowForDetachingTab( |
| tab_id_str_, group_id_str_, |
| base::BindOnce(&NewWindowForDetachingTabAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| void Cancel(crosapi::mojom::CreationResult reason) override { |
| DCHECK_NE(reason, mojom::CreationResult::kSuccess); |
| std::move(callback_).Run(reason, {}); |
| } |
| |
| private: |
| const std::u16string tab_id_str_; |
| const std::u16string group_id_str_; |
| NewWindowForDetachingTabCallback callback_; |
| base::WeakPtrFactory<NewWindowForDetachingTabAction> weak_ptr_factory_; |
| |
| void OnPerformed(BrowserManagerCallback on_performed, |
| mojom::CreationResult result, |
| const std::string& new_window) { |
| const bool retry = result == mojom::CreationResult::kBrowserShutdown; |
| if (!retry) { |
| std::move(callback_).Run(result, new_window); |
| } |
| std::move(on_performed).Run(retry); |
| } |
| }; |
| |
| class NewTabAction final : public BrowserAction { |
| public: |
| explicit NewTabAction(std::optional<uint64_t> profile_id = std::nullopt) |
| : BrowserAction(true), profile_id_(profile_id), weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| mojom::BrowserService::kNewTabMinVersion); |
| service.service->NewTab(profile_id_, |
| base::BindOnce(&NewTabAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| std::optional<uint64_t> profile_id_; |
| base::WeakPtrFactory<NewTabAction> weak_ptr_factory_; |
| }; |
| |
| class LaunchAction final : public BrowserAction { |
| public: |
| explicit LaunchAction(int64_t target_display_id, |
| std::optional<uint64_t> profile_id = std::nullopt) |
| : BrowserAction(true), |
| target_display_id_(target_display_id), |
| profile_id_(profile_id), |
| weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| mojom::BrowserService::kLaunchMinVersion); |
| service.service->Launch(target_display_id_, profile_id_, |
| base::BindOnce(&LaunchAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| int64_t target_display_id_; |
| std::optional<uint64_t> profile_id_; |
| base::WeakPtrFactory<LaunchAction> weak_ptr_factory_; |
| }; |
| |
| namespace { |
| crosapi::mojom::OpenUrlParams_SwitchToTabPathBehavior ConvertPathBehavior( |
| NavigateParams::PathBehavior path_behavior) { |
| switch (path_behavior) { |
| case NavigateParams::RESPECT: |
| return crosapi::mojom::OpenUrlParams_SwitchToTabPathBehavior::kRespect; |
| case NavigateParams::IGNORE_AND_NAVIGATE: |
| return crosapi::mojom::OpenUrlParams_SwitchToTabPathBehavior::kIgnore; |
| } |
| } |
| } // namespace |
| |
| class OpenUrlAction final : public BrowserAction { |
| public: |
| OpenUrlAction( |
| const GURL& url, |
| crosapi::mojom::OpenUrlParams::WindowOpenDisposition disposition, |
| crosapi::mojom::OpenUrlFrom from, |
| NavigateParams::PathBehavior path_behavior) |
| : BrowserAction(true), |
| url_(url), |
| disposition_(disposition), |
| from_(from), |
| path_behavior_(path_behavior), |
| weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| mojom::BrowserService::kOpenUrlMinVersion); |
| auto params = crosapi::mojom::OpenUrlParams::New(); |
| params->disposition = disposition_; |
| params->from = from_; |
| params->path_behavior = ConvertPathBehavior(path_behavior_); |
| service.service->OpenUrl(url_, std::move(params), |
| base::BindOnce(&OpenUrlAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| const GURL url_; |
| const crosapi::mojom::OpenUrlParams::WindowOpenDisposition disposition_; |
| const crosapi::mojom::OpenUrlFrom from_; |
| const NavigateParams::PathBehavior path_behavior_; |
| base::WeakPtrFactory<OpenUrlAction> weak_ptr_factory_; |
| }; |
| |
| class OpenCaptivePortalSigninAction final : public BrowserAction { |
| public: |
| explicit OpenCaptivePortalSigninAction(const GURL& url) |
| : BrowserAction(true), url_(url), weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| if (service.interface_version < |
| mojom::BrowserService::kOpenCaptivePortalSigninMinVersion) { |
| LOG(ERROR) << "BrowserService does not support OpenCaptivePortalSignin"; |
| return; |
| } |
| service.service->OpenCaptivePortalSignin( |
| url_, base::BindOnce(&OpenCaptivePortalSigninAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| const GURL url_; |
| base::WeakPtrFactory<OpenCaptivePortalSigninAction> weak_ptr_factory_; |
| }; |
| |
| class NewGuestWindowAction final : public BrowserAction { |
| public: |
| explicit NewGuestWindowAction(int64_t target_display_id) |
| : BrowserAction(true), |
| target_display_id_(target_display_id), |
| weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kNewGuestWindowMinVersion); |
| service.service->NewGuestWindow( |
| target_display_id_, base::BindOnce(&NewGuestWindowAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| const int64_t target_display_id_; |
| base::WeakPtrFactory<NewGuestWindowAction> weak_ptr_factory_; |
| }; |
| |
| class HandleTabScrubbingAction final : public BrowserAction { |
| public: |
| HandleTabScrubbingAction(float x_offset, bool is_fling_scroll_event) |
| : BrowserAction(false), |
| x_offset_(x_offset), |
| is_fling_scroll_event_(is_fling_scroll_event) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kHandleTabScrubbingMinVersion); |
| service.service->HandleTabScrubbing(x_offset_, is_fling_scroll_event_); |
| } |
| |
| private: |
| const float x_offset_; |
| const bool is_fling_scroll_event_; |
| }; |
| |
| class NewFullscreenWindowAction final : public BrowserAction { |
| public: |
| NewFullscreenWindowAction(const GURL& url, |
| int64_t target_display_id, |
| NewFullscreenWindowCallback callback) |
| : BrowserAction(true), |
| url_(url), |
| target_display_id_(target_display_id), |
| callback_(std::move(callback)), |
| weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kNewFullscreenWindowMinVersion); |
| service.service->NewFullscreenWindow( |
| url_, target_display_id_, |
| base::BindOnce(&NewFullscreenWindowAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| void Cancel(crosapi::mojom::CreationResult reason) override { |
| DCHECK_NE(reason, mojom::CreationResult::kSuccess); |
| std::move(callback_).Run(reason); |
| } |
| |
| private: |
| const GURL url_; |
| const int64_t target_display_id_; |
| NewFullscreenWindowCallback callback_; |
| base::WeakPtrFactory<NewFullscreenWindowAction> weak_ptr_factory_; |
| |
| void OnPerformed(BrowserManagerCallback on_performed, |
| mojom::CreationResult result) { |
| const bool retry = result == mojom::CreationResult::kBrowserShutdown; |
| if (!retry) { |
| std::move(callback_).Run(result); |
| } |
| std::move(on_performed).Run(retry); |
| } |
| }; |
| |
| class RestoreTabAction final : public BrowserAction { |
| public: |
| RestoreTabAction() : BrowserAction(true), weak_ptr_factory_(this) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kRestoreTabMinVersion); |
| service.service->RestoreTab(base::BindOnce(&RestoreTabAction::OnPerformed, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_performed))); |
| } |
| |
| private: |
| base::WeakPtrFactory<RestoreTabAction> weak_ptr_factory_; |
| }; |
| |
| class OpenForFullRestoreAction final : public BrowserAction { |
| public: |
| explicit OpenForFullRestoreAction(bool skip_crash_restore) |
| : BrowserAction(true), skip_crash_restore_(skip_crash_restore) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kOpenForFullRestoreMinVersion); |
| service.service->OpenForFullRestore(skip_crash_restore_); |
| } |
| |
| private: |
| const bool skip_crash_restore_; |
| }; |
| |
| class CreateBrowserWithRestoredDataAction final : public BrowserAction { |
| public: |
| CreateBrowserWithRestoredDataAction( |
| const std::vector<GURL>& urls, |
| const gfx::Rect& bounds, |
| const std::vector<tab_groups::TabGroupInfo>& tab_group_infos, |
| ui::WindowShowState show_state, |
| int32_t active_tab_index, |
| int32_t first_non_pinned_tab_index, |
| std::string_view app_name, |
| int32_t restore_window_id, |
| uint64_t lacros_profile_id) |
| : BrowserAction(true), |
| urls_(urls), |
| bounds_(bounds), |
| tab_group_infos_(tab_group_infos), |
| show_state_(show_state), |
| active_tab_index_(active_tab_index), |
| first_non_pinned_tab_index_(first_non_pinned_tab_index), |
| app_name_(app_name), |
| restore_window_id_(restore_window_id), |
| lacros_profile_id_(lacros_profile_id) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| crosapi::mojom::DeskTemplateStatePtr additional_state = |
| crosapi::mojom::DeskTemplateState::New( |
| urls_, active_tab_index_, app_name_, restore_window_id_, |
| first_non_pinned_tab_index_, tab_group_infos_, lacros_profile_id_); |
| crosapi::CrosapiManager::Get() |
| ->crosapi_ash() |
| ->desk_template_ash() |
| ->CreateBrowserWithRestoredData(bounds_, show_state_, |
| std::move(additional_state)); |
| } |
| |
| private: |
| const std::vector<GURL> urls_; |
| const gfx::Rect bounds_; |
| const std::vector<tab_groups::TabGroupInfo> tab_group_infos_; |
| const ui::WindowShowState show_state_; |
| const int32_t active_tab_index_; |
| const int32_t first_non_pinned_tab_index_; |
| const std::string app_name_; |
| const int32_t restore_window_id_; |
| const uint64_t lacros_profile_id_; |
| }; |
| |
| class OpenProfileManagerAction final : public BrowserAction { |
| public: |
| OpenProfileManagerAction() : BrowserAction(true) {} |
| |
| void Perform(const VersionedBrowserService& service, |
| BrowserManagerCallback on_performed) override { |
| CHECK_GE(service.interface_version, |
| crosapi::mojom::BrowserService::kOpenProfileManagerMinVersion); |
| service.service->OpenProfileManager(); |
| } |
| }; |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::NewWindow( |
| bool incognito, |
| bool should_trigger_session_restore, |
| int64_t target_display_id, |
| std::optional<uint64_t> profile_id) { |
| return std::make_unique<NewWindowAction>( |
| incognito, should_trigger_session_restore, target_display_id, profile_id); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::NewTab( |
| std::optional<uint64_t> profile_id) { |
| return std::make_unique<NewTabAction>(profile_id); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::Launch( |
| int64_t target_display_id, |
| std::optional<uint64_t> profile_id) { |
| return std::make_unique<LaunchAction>(target_display_id, profile_id); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::NewWindowForDetachingTab( |
| std::u16string_view tab_id_str, |
| std::u16string_view group_id_str, |
| NewWindowForDetachingTabCallback callback) { |
| return std::make_unique<NewWindowForDetachingTabAction>( |
| tab_id_str, group_id_str, std::move(callback)); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::NewGuestWindow( |
| int64_t target_display_id) { |
| return std::make_unique<NewGuestWindowAction>(target_display_id); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::NewFullscreenWindow( |
| const GURL& url, |
| int64_t target_display_id, |
| NewFullscreenWindowCallback callback) { |
| return std::make_unique<NewFullscreenWindowAction>(url, target_display_id, |
| std::move(callback)); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::OpenUrl( |
| const GURL& url, |
| crosapi::mojom::OpenUrlParams::WindowOpenDisposition disposition, |
| crosapi::mojom::OpenUrlFrom from, |
| NavigateParams::PathBehavior path_behavior) { |
| return std::make_unique<OpenUrlAction>(url, disposition, from, path_behavior); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::OpenCaptivePortalSignin( |
| const GURL& url) { |
| return std::make_unique<OpenCaptivePortalSigninAction>(url); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::OpenForFullRestore( |
| bool skip_crash_restore) { |
| return std::make_unique<OpenForFullRestoreAction>(skip_crash_restore); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::RestoreTab() { |
| return std::make_unique<RestoreTabAction>(); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::HandleTabScrubbing( |
| float x_offset, |
| bool is_fling_scroll_event) { |
| return std::make_unique<HandleTabScrubbingAction>(x_offset, |
| is_fling_scroll_event); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::CreateBrowserWithRestoredData( |
| const std::vector<GURL>& urls, |
| const gfx::Rect& bounds, |
| const std::vector<tab_groups::TabGroupInfo>& tab_groups, |
| ui::WindowShowState show_state, |
| int32_t active_tab_index, |
| int32_t first_non_pinned_tab_index, |
| std::string_view app_name, |
| int32_t restore_window_id, |
| uint64_t lacros_profile_id) { |
| return std::make_unique<CreateBrowserWithRestoredDataAction>( |
| urls, bounds, tab_groups, show_state, active_tab_index, |
| first_non_pinned_tab_index, app_name, restore_window_id, |
| lacros_profile_id); |
| } |
| |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::OpenProfileManager() { |
| return std::make_unique<OpenProfileManagerAction>(); |
| } |
| |
| // No window will be opened in the following circumstances: |
| // 1. Lacros-chrome is initialized in the Kiosk session. |
| // 2. Full restore is responsible for restoring/launching Lacros. |
| // 3. Floating Workspace Service is responsible for restoring/launching lacros. |
| // static |
| std::unique_ptr<BrowserAction> BrowserAction::GetActionForSessionStart() { |
| if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) { |
| return std::make_unique<NewWindowAction>( |
| /*incognito=*/false, /*should_trigger_session_restore=*/false, -1); |
| } |
| if (chromeos::IsKioskSession() || |
| ash::floating_workspace_util::ShouldHandleRestartRestore() || |
| ash::full_restore::MaybeCreateFullRestoreServiceForLacros()) { |
| return std::make_unique<NoOpAction>(); |
| } |
| return std::make_unique<NewWindowAction>( |
| /*incognito=*/false, /*should_trigger_session_restore=*/true, -1); |
| } |
| |
| |
| } // namespace crosapi |