#include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h"
#include <map>
#include <memory>
#include <type_traits>
#include <utility>
#include "base/check.h"
#include "base/check_op.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/one_shot_event.h"
#include "base/task/sequenced_task_runner.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/app_service/app_launch_params.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
#include "chrome/browser/ui/web_applications/web_app_dialogs.h"
#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
#include "chrome/browser/ui/web_applications/web_app_metrics.h"
#include "chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.h"
#include "chrome/browser/web_applications/web_app_callback_app_identity.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_pref_guardrails.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "chrome/browser/web_applications/web_app_uninstall_dialog_user_options.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/user_education/common/feature_promo_controller.h"
#include "components/user_education/common/feature_promo_data.h"
#include "components/webapps/browser/installable/installable_metrics.h"
#include "components/webapps/browser/uninstall_result_code.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/clear_site_data_utils.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/app_sorting.h"
#include "extensions/browser/extension_system.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom-shared.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/page_transition_types.h"
#include "ui/views/native_window_tracker.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "url/url_constants.h"
#if !BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h"
#include "chrome/browser/infobars/confirm_infobar_creator.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/infobar.h"
#else
#include "chrome/browser/ui/web_applications/web_app_relaunch_notification.h"
#endif
#if !BUILDFLAG(IS_MAC)
#include "ui/aura/window.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/public/cpp/shelf_model.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
#include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
#include "chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h"
#include "chromeos/ash/components/nonclosable_app_ui/nonclosable_app_ui_utils.h"
#include "components/sync/model/string_ordinal.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/ui/startup/first_run_service.h"
#include "chromeos/crosapi/mojom/web_app_service.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "mojo/public/cpp/bindings/remote.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "base/process/process.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/os_integration/web_app_shortcut.h"
#include "chrome/browser/web_applications/web_app_install_finalizer.h"
#include "components/keep_alive_registry/keep_alive_types.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#endif
namespace base {
class FilePath;
}
namespace web_app {
class AppLock;
namespace {
#if BUILDFLAG(IS_WIN)
void UninstallWebAppWithDialogFromStartupSwitch(
std::unique_ptr<ScopedKeepAlive> scoped_keep_alive,
const webapps::AppId& app_id,
WebAppProvider* provider) {
if (provider->registrar_unsafe().CanUserUninstallWebApp(app_id)) {
provider->ui_manager().PresentUserUninstallDialog(
app_id, webapps::WebappUninstallSource::kOsSettings,
gfx::NativeWindow(),
base::BindOnce(
[](std::unique_ptr<ScopedKeepAlive> scoped_keep_alive,
webapps::UninstallResultCode code) {
base::SequencedTaskRunner::GetCurrentDefault()->DeleteSoon(
FROM_HERE, std::move(scoped_keep_alive));
},
std::move(scoped_keep_alive)));
} else {
SynchronizeOsOptions synchronize_options;
synchronize_options.force_unregister_os_integration = true;
provider->scheduler().SynchronizeOsIntegration(
app_id,
base::BindOnce(
[](std::unique_ptr<ScopedKeepAlive> scoped_keep_alive) {},
std::move(scoped_keep_alive)),
synchronize_options);
}
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
void ShowNonclosableAppToast(const web_app::WebAppRegistrar& registrar,
const webapps::AppId& app_id) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto* const service = chromeos::LacrosService::Get();
if (!service->IsRegistered<crosapi::mojom::NonclosableAppToastService>() ||
!service->IsAvailable<crosapi::mojom::NonclosableAppToastService>()) {
return;
}
crosapi::mojom::NonclosableAppToastService* const
nonclosable_app_toast_service =
service->GetRemote<crosapi::mojom::NonclosableAppToastService>()
.get();
nonclosable_app_toast_service->OnUserAttemptedClose(
app_id, registrar.GetAppShortName(app_id));
#elif BUILDFLAG(IS_CHROMEOS_ASH)
ash::ShowNonclosableAppToast(app_id, registrar.GetAppShortName(app_id));
#endif
}
#endif
}
std::unique_ptr<WebAppUiManager> WebAppUiManager::Create(Profile* profile) { … }
WebAppUiManagerImpl::WebAppUiManagerImpl(Profile* profile)
: … { … }
WebAppUiManagerImpl::~WebAppUiManagerImpl() = default;
void WebAppUiManagerImpl::Start() { … }
void WebAppUiManagerImpl::Shutdown() { … }
WebAppUiManagerImpl* WebAppUiManagerImpl::AsImpl() { … }
size_t WebAppUiManagerImpl::GetNumWindowsForApp(const webapps::AppId& app_id) { … }
void WebAppUiManagerImpl::CloseAppWindows(const webapps::AppId& app_id) { … }
void WebAppUiManagerImpl::NotifyOnAllAppWindowsClosed(
const webapps::AppId& app_id,
base::OnceClosure callback) { … }
void WebAppUiManagerImpl::OnExtensionSystemReady() { … }
bool WebAppUiManagerImpl::CanAddAppToQuickLaunchBar() const { … }
void WebAppUiManagerImpl::AddAppToQuickLaunchBar(const webapps::AppId& app_id) { … }
bool WebAppUiManagerImpl::IsAppInQuickLaunchBar(
const webapps::AppId& app_id) const { … }
bool WebAppUiManagerImpl::IsInAppWindow(
content::WebContents* web_contents) const { … }
const webapps::AppId* WebAppUiManagerImpl::GetAppIdForWindow(
const content::WebContents* web_contents) const { … }
void WebAppUiManagerImpl::NotifyOnAssociatedAppChanged(
content::WebContents* web_contents,
const std::optional<webapps::AppId>& previous_app_id,
const std::optional<webapps::AppId>& new_app_id) const { … }
bool WebAppUiManagerImpl::CanReparentAppTabToWindow(
const webapps::AppId& app_id,
bool shortcut_created) const { … }
Browser* WebAppUiManagerImpl::ReparentAppTabToWindow(
content::WebContents* contents,
const webapps::AppId& app_id,
bool shortcut_created) { … }
void WebAppUiManagerImpl::ShowWebAppFileLaunchDialog(
const std::vector<base::FilePath>& file_paths,
const webapps::AppId& app_id,
WebAppLaunchAcceptanceCallback launch_callback) { … }
void WebAppUiManagerImpl::ShowWebAppIdentityUpdateDialog(
const std::string& app_id,
bool title_change,
bool icon_change,
const std::u16string& old_title,
const std::u16string& new_title,
const SkBitmap& old_icon,
const SkBitmap& new_icon,
content::WebContents* web_contents,
web_app::AppIdentityDialogCallback callback) { … }
void WebAppUiManagerImpl::ShowWebAppSettings(const webapps::AppId& app_id) { … }
void WebAppUiManagerImpl::LaunchWebApp(apps::AppLaunchParams params,
LaunchWebAppWindowSetting launch_setting,
Profile& profile,
LaunchWebAppDebugValueCallback callback,
WithAppResources& lock) { … }
void WebAppUiManagerImpl::WaitForFirstRunService(
Profile& profile,
FirstRunServiceCompletedCallback callback) { … }
#if BUILDFLAG(IS_CHROMEOS)
void WebAppUiManagerImpl::MigrateLauncherState(
const webapps::AppId& from_app_id,
const webapps::AppId& to_app_id,
base::OnceClosure callback) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto* lacros_service = chromeos::LacrosService::Get();
if (!lacros_service ||
lacros_service->GetInterfaceVersion<crosapi::mojom::WebAppService>() <
int{crosapi::mojom::WebAppService::MethodMinVersions::
kMigrateLauncherStateMinVersion}) {
LOG(WARNING) << "Ash version does not support MigrateLauncherState().";
std::move(callback).Run();
return;
}
lacros_service->GetRemote<crosapi::mojom::WebAppService>()
->MigrateLauncherState(from_app_id, to_app_id, std::move(callback));
#elif BUILDFLAG(IS_CHROMEOS_ASH)
auto* app_list_syncable_service =
app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
bool to_app_in_shelf =
app_list_syncable_service->GetPinPosition(to_app_id).IsValid();
if (!to_app_in_shelf) {
app_list_syncable_service->TransferItemAttributes(from_app_id, to_app_id);
}
std::move(callback).Run();
#else
static_assert(false);
#endif
}
void WebAppUiManagerImpl::DisplayRunOnOsLoginNotification(
const base::flat_map<webapps::AppId, RoolNotificationBehavior>& apps,
base::WeakPtr<Profile> profile) {
web_app::DisplayRunOnOsLoginNotification(apps, profile);
}
#endif
void WebAppUiManagerImpl::NotifyAppRelaunchState(
const webapps::AppId& placeholder_app_id,
const webapps::AppId& final_app_id,
const std::u16string& final_app_name,
base::WeakPtr<Profile> profile,
AppRelaunchState relaunch_state) { … }
content::WebContents* WebAppUiManagerImpl::CreateNewTab() { … }
bool WebAppUiManagerImpl::IsWebContentsActiveTabInBrowser(
content::WebContents* web_contents) { … }
void WebAppUiManagerImpl::TriggerInstallDialog(
content::WebContents* web_contents) { … }
void WebAppUiManagerImpl::PresentUserUninstallDialog(
const webapps::AppId& app_id,
webapps::WebappUninstallSource uninstall_source,
BrowserWindow* parent_window,
UninstallCompleteCallback callback) { … }
void WebAppUiManagerImpl::PresentUserUninstallDialog(
const webapps::AppId& app_id,
webapps::WebappUninstallSource uninstall_source,
gfx::NativeWindow native_window,
UninstallCompleteCallback callback) { … }
void WebAppUiManagerImpl::PresentUserUninstallDialog(
const webapps::AppId& app_id,
webapps::WebappUninstallSource uninstall_source,
gfx::NativeWindow parent_window,
UninstallCompleteCallback uninstall_complete_callback,
UninstallScheduledCallback uninstall_scheduled_callback) { … }
void WebAppUiManagerImpl::LaunchOrFocusIsolatedWebAppInstaller(
const base::FilePath& bundle_path) { … }
void WebAppUiManagerImpl::OnIsolatedWebAppInstallerClosed(
base::FilePath bundle_path) { … }
void WebAppUiManagerImpl::MaybeCreateEnableSupportedLinksInfobar(
content::WebContents* web_contents,
const std::string& launch_name) { … }
void WebAppUiManagerImpl::MaybeShowIPHPromoForAppsLaunchedViaLinkCapturing(
content::WebContents* web_contents,
Profile* profile,
const std::string& app_id) { … }
void WebAppUiManagerImpl::OnBrowserAdded(Browser* browser) { … }
#if BUILDFLAG(IS_CHROMEOS)
void WebAppUiManagerImpl::OnBrowserCloseCancelled(Browser* browser,
BrowserClosingStatus reason) {
DCHECK(started_);
if (!IsBrowserForInstalledApp(browser) ||
reason != BrowserClosingStatus::kDeniedByPolicy) {
return;
}
ShowNonclosableAppToast(
WebAppProvider::GetForWebApps(profile_)->registrar_unsafe(),
GetAppIdForBrowser(browser));
}
#endif
void WebAppUiManagerImpl::OnBrowserRemoved(Browser* browser) { … }
#if BUILDFLAG(IS_CHROMEOS)
void WebAppUiManagerImpl::TabCloseCancelled(
const content::WebContents* contents) {
const webapps::AppId* app_id = GetAppIdForWindow(contents);
if (!app_id) {
return;
}
ShowNonclosableAppToast(
WebAppProvider::GetForWebApps(profile_)->registrar_unsafe(), *app_id);
}
#endif
#if BUILDFLAG(IS_WIN)
void WebAppUiManagerImpl::UninstallWebAppFromStartupSwitch(
const webapps::AppId& app_id) {
WebAppProvider* provider = WebAppProvider::GetForWebApps(profile_);
provider->on_registry_ready().Post(
FROM_HERE, base::BindOnce(&UninstallWebAppWithDialogFromStartupSwitch,
std::make_unique<ScopedKeepAlive>(
KeepAliveOrigin::WEB_APP_UNINSTALL,
KeepAliveRestartOption::DISABLED),
app_id, provider));
}
#endif
bool WebAppUiManagerImpl::IsBrowserForInstalledApp(Browser* browser) { … }
webapps::AppId WebAppUiManagerImpl::GetAppIdForBrowser(Browser* browser) { … }
void WebAppUiManagerImpl::OnIconsReadForUninstall(
const webapps::AppId& app_id,
webapps::WebappUninstallSource uninstall_source,
gfx::NativeWindow parent_window,
std::unique_ptr<views::NativeWindowTracker> parent_window_tracker,
UninstallCompleteCallback complete_callback,
UninstallScheduledCallback uninstall_scheduled_callback,
std::map<SquareSizePx, SkBitmap> icon_bitmaps) { … }
void WebAppUiManagerImpl::ScheduleUninstallIfUserRequested(
const webapps::AppId& app_id,
webapps::WebappUninstallSource uninstall_source,
UninstallCompleteCallback complete_callback,
UninstallScheduledCallback uninstall_scheduled_callback,
web_app::UninstallUserOptions uninstall_options) { … }
void WebAppUiManagerImpl::OnUninstallCancelled(
UninstallCompleteCallback complete_callback,
UninstallScheduledCallback uninstall_scheduled_callback) { … }
void WebAppUiManagerImpl::ClearWebAppSiteDataIfNeeded(
const GURL app_start_url,
UninstallCompleteCallback uninstall_complete_callback,
webapps::UninstallResultCode uninstall_code) { … }
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
void WebAppUiManagerImpl::ShowIPHPromoForAppsLaunchedViaLinkCapturing(
const Browser* browser,
const webapps::AppId& app_id,
bool is_activated) { … }
void WebAppUiManagerImpl::OnIPHPromoResponseForLinkCapturing(
const Browser* browser,
const webapps::AppId& app_id) { … }
#endif
}