chromium/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc

// Copyright 2021 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/web_applications/app_service/web_app_publisher_helper.h"

#include <stddef.h>

#include <iterator>
#include <memory>
#include <ostream>
#include <set>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>

#include "base/check.h"
#include "base/check_op.h"
#include "base/containers/checked_iterators.h"
#include "base/containers/contains.h"
#include "base/containers/extend.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/flat_tree.h"
#include "base/containers/map_util.h"
#include "base/containers/span.h"
#include "base/containers/to_vector.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/concurrent_callbacks.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/one_shot_event.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_launch_params.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/intent_util.h"
#include "chrome/browser/apps/app_service/launch_utils.h"
#include "chrome/browser/apps/app_service/policy_util.h"
#include "chrome/browser/apps/app_service/publishers/app_publisher.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/app_service/publisher_helper.h"
#include "chrome/browser/web_applications/commands/compute_app_size_command.h"
#include "chrome/browser/web_applications/locks/app_lock.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/proto/web_app_proto_package.pb.h"
#include "chrome/browser/web_applications/scope_extension_info.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_chromeos_data.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_helpers.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_sync_bridge.h"
#include "chrome/browser/web_applications/web_app_tab_helper.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/chrome_features.h"
#include "components/content_settings/core/browser/content_settings_type_set.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/icon_effects.h"
#include "components/services/app_service/public/cpp/intent_filter.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "components/services/app_service/public/cpp/run_on_os_login_types.h"
#include "components/services/app_service/public/cpp/share_target.h"
#include "components/webapps/browser/installable/installable_metrics.h"
#include "content/public/browser/clear_site_data_utils.h"
#include "content/public/browser/storage_partition_config.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "net/cookies/cookie_partition_key.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
#include "ui/base/window_open_disposition.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/native_widget_types.h"
#include "url/gurl.h"
#include "url/origin.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/apps/browser_instance/browser_app_instance_tracker.h"
#include "chrome/browser/badging/badge_manager.h"
#include "chrome/browser/badging/badge_manager_factory.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/notifications/notification_display_service_factory.h"
#include "chrome/browser/web_applications/chromeos_web_app_experiments.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notifier_id.h"
#endif

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/webui/projector_app/public/cpp/projector_app_constants.h"  // nogncheck
#include "ash/webui/system_apps/public/system_web_app_type.h"
#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/ash/file_manager/app_id.h"
#include "chrome/browser/ash/guest_os/guest_os_terminal.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
#include "chrome/browser/ash/system_web_apps/types/system_web_app_data.h"
#include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h"
#include "chrome/browser/chromeos/arc/arc_web_contents_data.h"  // nogncheck
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/full_restore_save_handler.h"
#include "components/app_restore/full_restore_utils.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/sessions/core/session_id.h"
#include "extensions/browser/api/file_handlers/mime_util.h"  // nogncheck
#endif

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_service.h"
#endif

IconEffects;

namespace content {
class BrowserContext;
}

namespace ui {
enum ResourceScaleFactor : int;
}

namespace web_app {

namespace {

// Only supporting important permissions for now.
const ContentSettingsType kSupportedPermissionTypes[] =;

// Mime Type for plain text.
const char kTextPlain[] =;

bool GetContentSettingsType(apps::PermissionType permission_type,
                            ContentSettingsType& content_setting_type) {}

apps::PermissionType GetPermissionType(
    ContentSettingsType content_setting_type) {}

apps::InstallReason GetHighestPriorityInstallReason(const WebApp* web_app) {}

apps::InstallSource GetInstallSource(
    std::optional<webapps::WebappInstallSource> source) {}

apps::Readiness ConvertWebappUninstallSourceToReadiness(
    webapps::WebappUninstallSource source) {}

bool IsNoteTakingWebApp(const WebApp& web_app) {}

bool IsLockScreenCapable(const WebApp& web_app) {}

apps::IntentFilterPtr CreateMimeTypeShareFilter(
    const std::vector<std::string>& mime_types) {}

apps::IntentFilterPtr CreateIntentFilterFromOrigin(
    const url::Origin& origin,
    bool add_subdomain_wildcard) {}

apps::IntentFilters CreateIntentFiltersFromScopeExtensionInfo(
    const web_app::ScopeExtensionInfo& scope_extension_info) {}

apps::IntentFilters CreateShareIntentFiltersFromShareTarget(
    const apps::ShareTarget& share_target) {}

apps::IntentFilters CreateIntentFiltersFromFileHandlers(
    const apps::FileHandlers& file_handlers) {}

}  // namespace

void UninstallImpl(WebAppProvider* provider,
                   const std::string& app_id,
                   apps::UninstallSource uninstall_source,
                   gfx::NativeWindow parent_window) {}

WebAppPublisherHelper::Delegate::Delegate() = default;

WebAppPublisherHelper::Delegate::~Delegate() = default;

#if BUILDFLAG(IS_CHROMEOS)
WebAppPublisherHelper::BadgeManagerDelegate::BadgeManagerDelegate(
    const base::WeakPtr<WebAppPublisherHelper>& publisher_helper)
    : badging::BadgeManagerDelegate(publisher_helper->profile(),
                                    publisher_helper->badge_manager_),
      publisher_helper_(publisher_helper) {}

WebAppPublisherHelper::BadgeManagerDelegate::~BadgeManagerDelegate() = default;

void WebAppPublisherHelper::BadgeManagerDelegate::OnAppBadgeUpdated(
    const webapps::AppId& app_id) {
  if (!publisher_helper_) {
    return;
  }
  apps::AppPtr app =
      publisher_helper_->app_notifications_.CreateAppWithHasBadgeStatus(
          publisher_helper_->app_type(), app_id);
  DCHECK(app->has_badge.has_value());
  app->has_badge =
      publisher_helper_->ShouldShowBadge(app_id, app->has_badge.value());
  publisher_helper_->delegate_->PublishWebApp(std::move(app));
}
#endif

WebAppPublisherHelper::WebAppPublisherHelper(Profile* profile,
                                             WebAppProvider* provider,
                                             Delegate* delegate)
    :{}

WebAppPublisherHelper::~WebAppPublisherHelper() = default;

// static
apps::AppType WebAppPublisherHelper::GetWebAppType() {}

// static
bool WebAppPublisherHelper::IsSupportedWebAppPermissionType(
    ContentSettingsType permission_type) {}

void WebAppPublisherHelper::Shutdown() {}

void WebAppPublisherHelper::SetWebAppShowInFields(const WebApp* web_app,
                                                  apps::App& app) {}

apps::Permissions WebAppPublisherHelper::CreatePermissions(
    const WebApp* web_app) {}

// static
apps::IntentFilters WebAppPublisherHelper::CreateIntentFiltersForWebApp(
    const WebAppProvider& provider,
    const web_app::WebApp& app) {}

apps::AppPtr WebAppPublisherHelper::CreateWebApp(const WebApp* web_app) {}

apps::AppPtr WebAppPublisherHelper::ConvertUninstalledWebApp(
    const webapps::AppId& app_id,
    webapps::WebappUninstallSource uninstall_source) {}

apps::AppPtr WebAppPublisherHelper::ConvertLaunchedWebApp(
    const WebApp* web_app) {}

void WebAppPublisherHelper::UninstallWebApp(
    const WebApp* web_app,
    apps::UninstallSource uninstall_source,
    bool clear_site_data,
    bool report_abuse) {}

void WebAppPublisherHelper::SetIconEffect(const std::string& app_id) {}

#if BUILDFLAG(IS_CHROMEOS)
void WebAppPublisherHelper::PauseApp(const std::string& app_id) {
  if (IsShuttingDown()) {
    return;
  }

  if (paused_apps_.MaybeAddApp(app_id)) {
    SetIconEffect(app_id);
  }

  if (!IsWebAppsCrosapiEnabled()) {
    provider_->ui_manager().CloseAppWindows(app_id);
  } else {
    CHECK(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
        profile_));

    apps::BrowserAppInstanceTracker* instance_tracker =
        apps::AppServiceProxyFactory::GetForProfile(profile_)
            ->BrowserAppInstanceTracker();
    CHECK(instance_tracker);

    instance_tracker->StopInstancesOfApp(app_id);
  }

  delegate_->PublishWebApp(paused_apps_.CreateAppWithPauseStatus(
      app_type(), app_id, /*paused=*/true));
}

void WebAppPublisherHelper::UnpauseApp(const std::string& app_id) {
  if (IsShuttingDown()) {
    return;
  }

  if (paused_apps_.MaybeRemoveApp(app_id)) {
    SetIconEffect(app_id);
  }

  delegate_->PublishWebApp(paused_apps_.CreateAppWithPauseStatus(
      app_type(), app_id, /*paused=*/false));
}

bool WebAppPublisherHelper::IsPaused(const std::string& app_id) {
  return paused_apps_.IsPaused(app_id);
}

void WebAppPublisherHelper::StopApp(const std::string& app_id) {
  if (IsShuttingDown()) {
    return;
  }

  if (!IsWebAppsCrosapiEnabled()) {
    provider_->ui_manager().CloseAppWindows(app_id);
    return;
  }

  CHECK(
      apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile_));

  apps::BrowserAppInstanceTracker* instance_tracker =
      apps::AppServiceProxyFactory::GetForProfile(profile_)
          ->BrowserAppInstanceTracker();
  CHECK(instance_tracker);

  instance_tracker->StopInstancesOfApp(app_id);
}

void WebAppPublisherHelper::GetCompressedIconData(
    const std::string& app_id,
    int32_t size_in_dip,
    ui::ResourceScaleFactor scale_factor,
    apps::LoadIconCallback callback) {
  DCHECK(provider_);
  if (IsShuttingDown()) {
    return;
  }

  apps::GetWebAppCompressedIconData(profile_, app_id, size_in_dip, scale_factor,
                                    std::move(callback));
}
#endif  // BUILDFLAG(IS_CHROMEOS)

void WebAppPublisherHelper::LoadIcon(const std::string& app_id,
                                     apps::IconType icon_type,
                                     int32_t size_hint_in_dip,
                                     apps::IconEffects icon_effects,
                                     apps::LoadIconCallback callback) {}

void WebAppPublisherHelper::Launch(
    const std::string& app_id,
    int32_t event_flags,
    apps::LaunchSource launch_source,
    apps::WindowInfoPtr window_info,
    base::OnceCallback<void(content::WebContents*)> on_complete) {}

void WebAppPublisherHelper::LaunchAppWithFiles(
    const std::string& app_id,
    int32_t event_flags,
    apps::LaunchSource launch_source,
    std::vector<base::FilePath> file_paths) {}

void WebAppPublisherHelper::LaunchAppWithIntent(
    const std::string& app_id,
    int32_t event_flags,
    apps::IntentPtr intent,
    apps::LaunchSource launch_source,
    apps::WindowInfoPtr window_info,
    apps::LaunchCallback callback) {}

void WebAppPublisherHelper::LaunchAppWithParams(
    apps::AppLaunchParams params,
    base::OnceCallback<void(content::WebContents*)> on_complete) {}

void WebAppPublisherHelper::SetPermission(const std::string& app_id,
                                          apps::PermissionPtr permission) {}

void WebAppPublisherHelper::OpenNativeSettings(const std::string& app_id) {}

apps::WindowMode WebAppPublisherHelper::GetWindowMode(
    const std::string& app_id) {}

void WebAppPublisherHelper::UpdateAppSize(const std::string& app_id) {}

void WebAppPublisherHelper::SetWindowMode(const std::string& app_id,
                                          apps::WindowMode window_mode) {}

apps::WindowMode WebAppPublisherHelper::ConvertDisplayModeToWindowMode(
    blink::mojom::DisplayMode display_mode) {}

void WebAppPublisherHelper::PublishWindowModeUpdate(
    const std::string& app_id,
    blink::mojom::DisplayMode display_mode) {}

void WebAppPublisherHelper::PublishRunOnOsLoginModeUpdate(
    const std::string& app_id,
    RunOnOsLoginMode run_on_os_login_mode) {}

std::string WebAppPublisherHelper::GenerateShortcutId() {}

void WebAppPublisherHelper::StoreShortcutId(
    const std::string& shortcut_id,
    const WebAppShortcutsMenuItemInfo& menu_item_info) {}

void WebAppPublisherHelper::ExecuteContextMenuCommand(
    const std::string& app_id,
    const std::string& shortcut_id,
    int64_t display_id,
    base::OnceCallback<void(content::WebContents*)> on_complete) {}

WebAppRegistrar& WebAppPublisherHelper::registrar() const {}

WebAppInstallManager& WebAppPublisherHelper::install_manager() const {}

bool WebAppPublisherHelper::IsShuttingDown() const {}

void WebAppPublisherHelper::OnWebAppFileHandlerApprovalStateChanged(
    const webapps::AppId& app_id) {}

void WebAppPublisherHelper::OnWebAppInstalled(const webapps::AppId& app_id) {}

void WebAppPublisherHelper::OnWebAppInstalledWithOsHooks(
    const webapps::AppId& app_id) {}

void WebAppPublisherHelper::OnWebAppManifestUpdated(
    const webapps::AppId& app_id) {}

void WebAppPublisherHelper::OnWebAppUninstalled(
    const webapps::AppId& app_id,
    webapps::WebappUninstallSource uninstall_source) {}

void WebAppPublisherHelper::OnWebAppInstallManagerDestroyed() {}

void WebAppPublisherHelper::OnAppRegistrarDestroyed() {}

void WebAppPublisherHelper::OnWebAppLastLaunchTimeChanged(
    const std::string& app_id,
    const base::Time& last_launch_time) {}

void WebAppPublisherHelper::OnWebAppUserDisplayModeChanged(
    const webapps::AppId& app_id,
    mojom::UserDisplayMode user_display_mode) {}

void WebAppPublisherHelper::OnWebAppRunOnOsLoginModeChanged(
    const webapps::AppId& app_id,
    RunOnOsLoginMode run_on_os_login_mode) {}

#if BUILDFLAG(IS_CHROMEOS)
// If is_disabled is set, the app backed by |app_id| is published with readiness
// kDisabledByPolicy, otherwise it's published with readiness kReady.
void WebAppPublisherHelper::OnWebAppDisabledStateChanged(
    const webapps::AppId& app_id,
    bool is_disabled) {
  const WebApp* web_app = GetWebApp(app_id);
  if (!web_app) {
    return;
  }

  DCHECK_EQ(is_disabled, web_app->chromeos_data()->is_disabled);
  apps::AppPtr app = CreateWebApp(web_app);
  app->icon_key = apps::IconKey(GetIconEffects(web_app));

  // If the disable mode is hidden, update the visibility of the new disabled
  // app.
  if (is_disabled && provider_->policy_manager().IsDisabledAppsModeHidden()) {
    UpdateAppDisabledMode(*app);
  }

  delegate_->PublishWebApp(std::move(app));
}

void WebAppPublisherHelper::OnWebAppsDisabledModeChanged() {
  std::vector<apps::AppPtr> apps;
  std::vector<webapps::AppId> app_ids = registrar().GetAppIds();
  for (const auto& id : app_ids) {
    // We only update visibility of disabled apps in this method. When enabling
    // previously disabled app, OnWebAppDisabledStateChanged() method will be
    // called and this method will update visibility and readiness of the newly
    // enabled app.
    if (provider_->policy_manager().IsWebAppInDisabledList(id)) {
      const WebApp* web_app = GetWebApp(id);
      if (!web_app) {
        continue;
      }
      auto app = std::make_unique<apps::App>(app_type(), web_app->app_id());
      UpdateAppDisabledMode(*app);
      apps.push_back(std::move(app));
    }
  }
  delegate_->PublishWebApps(std::move(apps));
}
#endif

#if BUILDFLAG(IS_CHROMEOS)
void WebAppPublisherHelper::OnNotificationDisplayed(
    const message_center::Notification& notification,
    const NotificationCommon::Metadata* const metadata) {
  if (notification.notifier_id().type !=
      message_center::NotifierType::WEB_PAGE) {
    return;
  }
  MaybeAddWebPageNotifications(notification, metadata);
}

void WebAppPublisherHelper::OnNotificationClosed(
    const std::string& notification_id) {
  auto app_ids = app_notifications_.GetAppIdsForNotification(notification_id);
  if (app_ids.empty()) {
    return;
  }

  app_notifications_.RemoveNotification(notification_id);

  for (const auto& app_id : app_ids) {
    auto app =
        app_notifications_.CreateAppWithHasBadgeStatus(app_type(), app_id);
    DCHECK(app->has_badge.has_value());
    app->has_badge = ShouldShowBadge(app_id, app->has_badge.value());
    delegate_->PublishWebApp(std::move(app));
  }
}

void WebAppPublisherHelper::OnNotificationDisplayServiceDestroyed(
    NotificationDisplayService* service) {
  DCHECK(notification_display_service_.IsObservingSource(service));
  notification_display_service_.Reset();
}

void WebAppPublisherHelper::OnIsCapturingVideoChanged(
    content::WebContents* web_contents,
    bool is_capturing_video) {
  const webapps::AppId* app_id = WebAppTabHelper::GetAppId(web_contents);
  if (!app_id) {
    return;
  }
  auto result = media_requests_.UpdateCameraState(*app_id, web_contents,
                                                  is_capturing_video);
  delegate_->ModifyWebAppCapabilityAccess(*app_id, result.camera,
                                          result.microphone);
}

void WebAppPublisherHelper::OnIsCapturingAudioChanged(
    content::WebContents* web_contents,
    bool is_capturing_audio) {
  const webapps::AppId* app_id = WebAppTabHelper::GetAppId(web_contents);
  if (!app_id) {
    return;
  }
  auto result = media_requests_.UpdateMicrophoneState(*app_id, web_contents,
                                                      is_capturing_audio);
  delegate_->ModifyWebAppCapabilityAccess(*app_id, result.camera,
                                          result.microphone);
}
#endif

void WebAppPublisherHelper::OnContentSettingChanged(
    const ContentSettingsPattern& primary_pattern,
    const ContentSettingsPattern& secondary_pattern,
    ContentSettingsTypeSet content_type_set) {}

void WebAppPublisherHelper::OnWebAppSettingsPolicyChanged() {}

void WebAppPublisherHelper::Init() {}

void WebAppPublisherHelper::ObserveWebAppSubsystems() {}

IconEffects WebAppPublisherHelper::GetIconEffects(const WebApp* web_app) {}

const WebApp* WebAppPublisherHelper::GetWebApp(
    const webapps::AppId& app_id) const {}

void WebAppPublisherHelper::LaunchAppWithIntentImpl(
    const std::string& app_id,
    int32_t event_flags,
    apps::IntentPtr intent,
    apps::LaunchSource launch_source,
    int64_t display_id,
    base::OnceCallback<void(std::vector<content::WebContents*>)> callback) {}

std::vector<std::string> WebAppPublisherHelper::GetPolicyIds(
    const WebApp& web_app) const {}

apps::PackageId WebAppPublisherHelper::GetPackageId(
    const WebApp& web_app) const {}

#if BUILDFLAG(IS_CHROMEOS)
void WebAppPublisherHelper::UpdateAppDisabledMode(apps::App& app) {
  if (provider_->policy_manager().IsDisabledAppsModeHidden()) {
    app.show_in_launcher = false;
    app.show_in_search = false;
    app.show_in_shelf = false;
    return;
  }
  app.show_in_launcher = true;
  app.show_in_search = true;
  app.show_in_shelf = true;

#if BUILDFLAG(IS_CHROMEOS_ASH)
  auto* swa_manager = ash::SystemWebAppManager::Get(profile());
  if (!swa_manager) {
    return;
  }
  auto system_app_type = swa_manager->GetSystemAppTypeForAppId(app.app_id);
  if (system_app_type.has_value()) {
    auto* system_app = swa_manager->GetSystemApp(*system_app_type);
    DCHECK(system_app);
    app.show_in_launcher = system_app->ShouldShowInLauncher();
    app.show_in_shelf = system_app->ShouldShowInSearchAndShelf();
    app.show_in_search = system_app->ShouldShowInSearchAndShelf();
  }
#endif
}

bool WebAppPublisherHelper::MaybeAddNotification(
    const std::string& app_id,
    const std::string& notification_id) {
  const WebApp* web_app = GetWebApp(app_id);
  if (!web_app) {
    return false;
  }

  app_notifications_.AddNotification(app_id, notification_id);
  auto app = app_notifications_.CreateAppWithHasBadgeStatus(app_type(), app_id);
  DCHECK(app->has_badge.has_value());
  app->has_badge = ShouldShowBadge(app_id, app->has_badge.value());
  delegate_->PublishWebApp(std::move(app));
  return true;
}

void WebAppPublisherHelper::MaybeAddWebPageNotifications(
    const message_center::Notification& notification,
    const NotificationCommon::Metadata* const metadata) {
  const PersistentNotificationMetadata* persistent_metadata =
      PersistentNotificationMetadata::From(metadata);

  const NonPersistentNotificationMetadata* non_persistent_metadata =
      NonPersistentNotificationMetadata::From(metadata);

  if (persistent_metadata) {
    // For persistent notifications, find the web app with the SW scope url.
    std::optional<webapps::AppId> app_id = FindInstalledAppWithUrlInScope(
        profile(), persistent_metadata->service_worker_scope,
        /*window_only=*/false);
    if (app_id.has_value()) {
      MaybeAddNotification(app_id.value(), notification.id());
    }
  } else {
    // For non-persistent notifications, find all web apps that are installed
    // under the origin url.

    const GURL& url = non_persistent_metadata &&
                              !non_persistent_metadata->document_url.is_empty()
                          ? non_persistent_metadata->document_url
                          : notification.origin_url();

    auto app_ids = registrar().FindAppsInScope(url);
    for (const auto& app_id : app_ids) {
      MaybeAddNotification(app_id, notification.id());
    }
  }
}

bool WebAppPublisherHelper::ShouldShowBadge(const std::string& app_id,
                                            bool has_notification) {
  // We show a badge if either the Web Badging API recently has a badge set, or
  // the Badging API has not been recently used by the app and a notification is
  // showing.
  if (!badge_manager_ || !badge_manager_->HasRecentApiUsage(app_id)) {
    return has_notification;
  }

  return badge_manager_->GetBadgeValue(app_id).has_value();
}
#endif

void WebAppPublisherHelper::LaunchAppWithFilesCheckingUserPermission(
    const std::string& app_id,
    apps::AppLaunchParams params,
    base::OnceCallback<void(std::vector<content::WebContents*>)> callback) {}

void WebAppPublisherHelper::OnFileHandlerDialogCompleted(
    std::string app_id,
    apps::AppLaunchParams params,
    base::OnceCallback<void(std::vector<content::WebContents*>)> callback,
    bool allowed,
    bool remember_user_choice) {}

void WebAppPublisherHelper::OnLaunchCompleted(
    apps::AppLaunchParams params_for_restore,
    bool is_system_web_app,
    std::optional<GURL> override_url,
    base::OnceCallback<void(content::WebContents*)> on_complete,
    base::WeakPtr<Browser> browser,
    base::WeakPtr<content::WebContents> web_contents,
    apps::LaunchContainer container) {}

void WebAppPublisherHelper::OnGetWebAppSize(
    webapps::AppId app_id,
    std::optional<ComputedAppSize> size) {}

}  // namespace web_app