chromium/chrome/browser/ui/web_applications/web_app_relaunch_notification.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/web_applications/web_app_relaunch_notification.h"

#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/notifications/system_notification_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/webui_url_constants.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "components/webapps/common/web_app_id.h"
#include "ui/base/l10n/l10n_util.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/notifier_catalogs.h"
#endif

namespace web_app {

namespace {

constexpr char kWebAppRelaunchId[] = "web_app_relaunch";
constexpr char kWebAppRelaunchNotifierIdPrefix[] = "web_app_relaunch_notifier";

std::string CreateNotificationId(const webapps::AppId& placeholder_app_id) {
  return base::StrCat(
      {kWebAppRelaunchNotifierIdPrefix, ":", placeholder_app_id});
}

message_center::Notification CreateNotification(
    const webapps::AppId& placeholder_app_id,
    const webapps::AppId& final_app_id,
    const std::u16string& final_app_name) {
#if (BUILDFLAG(IS_CHROMEOS_ASH))
  message_center::NotifierId notifier_id = message_center::NotifierId(
      message_center::NotifierType::SYSTEM_COMPONENT, kWebAppRelaunchId,
      ash::NotificationCatalogName::kWebAppSettings);
#else
  message_center::NotifierId notifier_id = message_center::NotifierId(
      message_center::NotifierType::SYSTEM_COMPONENT, kWebAppRelaunchId);
#endif  // (BUILDFLAG(IS_CHROMEOS_ASH))

  message_center::Notification notification(
      message_center::NOTIFICATION_TYPE_SIMPLE,
      CreateNotificationId(placeholder_app_id),
      l10n_util::GetStringFUTF16(IDS_WEB_APP_RELAUNCH_NOTIFICATION_TITLE,
                                 final_app_name),
      l10n_util::GetStringUTF16(IDS_WEB_APP_RELAUNCH_NOTIFICATION_MESSAGE),
      ui::ImageModel(),
      /* display_source= */ std::u16string(),
      /* origin_url */ GURL(), std::move(notifier_id),
      message_center::RichNotificationData(),
      base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
          message_center::HandleNotificationClickDelegate::ButtonClickCallback(
              base::DoNothing())));
  notification.SetSystemPriority();
  return notification;
}

}  // namespace

void 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) {
  if (!profile) {
    return;
  }

  switch (relaunch_state) {
    case web_app::AppRelaunchState::kAppClosingForRelaunch:
      NotificationDisplayService::GetForProfile(profile.get())
          ->Display(NotificationHandler::Type::TRANSIENT,
                    std::move(CreateNotification(placeholder_app_id,
                                                 final_app_id, final_app_name)),
                    /*metadata=*/nullptr);
      break;
    case web_app::AppRelaunchState::kAppAboutToRelaunch:
      // TODO(b/311711416): Implement progress bar.
      break;
    case web_app::AppRelaunchState::kAppRelaunched:
      scoped_refptr<base::SingleThreadTaskRunner> task_runner;
      if (GetTaskRunnerForTesting()) {            // IN-TEST
        task_runner = GetTaskRunnerForTesting();  // IN-TEST
      } else {
        task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
      }
      task_runner->PostDelayedTask(
          FROM_HERE,
          base::BindOnce(
              [](webapps::AppId app_id, base::WeakPtr<Profile> profile) {
                if (!profile) {
                  return;
                }

                // The `NotificationDisplayService::Close` function can be
                // called even if
                // the notification is not shown anymore.
                NotificationDisplayService::GetForProfile(profile.get())
                    ->Close(NotificationHandler::Type::TRANSIENT,
                            CreateNotificationId(app_id));
              },
              placeholder_app_id, std::move(profile)),
          base::Seconds(kSecondsToShowNotificationPostAppRelaunch));
      break;
  }
}

scoped_refptr<base::SingleThreadTaskRunner>& GetTaskRunnerForTesting() {
  static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>>
      task_runner_for_testing;
  return *task_runner_for_testing;
}

}  // namespace web_app