chromium/chrome/browser/apps/app_service/promise_apps/promise_app_service.h

// 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.

#ifndef CHROME_BROWSER_APPS_APP_SERVICE_PROMISE_APPS_PROMISE_APP_SERVICE_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_PROMISE_APPS_PROMISE_APP_SERVICE_H_

#include <memory>
#include <optional>

#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/apps/app_service/promise_apps/promise_app_icon_cache.h"
#include "chrome/browser/ash/apps/apk_web_app_service.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/icon_effects.h"

class Profile;

namespace gfx {
class Image;
}
namespace image_fetcher {
class ImageFetcher;
struct RequestMetadata;
}  // namespace image_fetcher

namespace apps {

struct PromiseApp;
struct IconValue;

class PromiseAppIcon;
class PromiseAppIconCache;

class PackageId;
class PromiseAppAlmanacConnector;
class PromiseAppRegistryCache;
class PromiseAppWrapper;

using PromiseAppPtr = std::unique_ptr<PromiseApp>;
using PromiseAppIconPtr = std::unique_ptr<PromiseAppIcon>;
using IconValuePtr = std::unique_ptr<IconValue>;

using IconDownloadedCallback =
    base::OnceCallback<void(const gfx::Image& image,
                            const image_fetcher::RequestMetadata& metadata)>;

// This service is responsible for registering and managing promise apps,
// including retrieving any data required to populate a promise app object.
// These promise apps will result in a "promise icon" that the user sees in the
// Launcher/ Shelf, which represents a pending or active app installation.
class PromiseAppService : public AppRegistryCache::Observer {
 public:
  explicit PromiseAppService(Profile* profile,
                             AppRegistryCache& app_registry_cache);

  PromiseAppService(const PromiseAppService&) = delete;
  PromiseAppService& operator=(const PromiseAppService&) = delete;
  ~PromiseAppService() override;

  apps::PromiseAppRegistryCache* PromiseAppRegistryCache();

  apps::PromiseAppIconCache* PromiseAppIconCache();

  // Adds or updates a promise app in the Promise App Registry Cache with the
  // fields provided in `delta`. For new promise app registrations, we send a
  // request to the Almanac API to retrieve additional promise app info.
  void OnPromiseApp(PromiseAppPtr delta);

  // Retrieves the icon for a package ID and applies any specified effects.
  void LoadIcon(const PackageId& package_id,
                int32_t size_hint_in_dip,
                apps::IconEffects icon_effects,
                apps::LoadIconCallback callback);

  // apps::AppRegistryCache::Observer overrides:
  void OnAppUpdate(const apps::AppUpdate& update) override;
  void OnAppRegistryCacheWillBeDestroyed(
      apps::AppRegistryCache* cache) override;

  void OnApkWebAppInstallationFinished(const std::string& package_name);

  // Allows us to skip Almanac implementation when running unit tests that don't
  // care about Almanac responses.
  void SetSkipAlmanacForTesting(bool skip_almanac);

  // Allows tests to trigger an Almanac query without needing an official Google
  // API key.
  void SetSkipApiKeyCheckForTesting(bool skip_api_key_check);

  // Tries to update install priroity if possible for ARC apps.
  void UpdateInstallPriority(const std::string& id);

 private:
  // Update a promise app's fields with the info retrieved from the Almanac API.
  void OnGetPromiseAppInfoCompleted(
      const PackageId& package_id,
      std::optional<PromiseAppWrapper> promise_app_info);

  // Adds an icon to the icon cache and marks the corresponding promise app
  // as ready to show after all the icons are downloaded.
  void OnIconDownloaded(const PackageId& package_id,
                        const gfx::Image& image,
                        const image_fetcher::RequestMetadata& metadata);

  // Check whether there is a registered app in AppRegistryCache with the
  // specified package ID.
  bool IsRegisteredInAppRegistryCache(const PackageId& package_id);

  // Set `should_show` to true for a promise app.
  void SetPromiseAppReadyToShow(const PackageId& package_id);

  raw_ptr<Profile> profile_;

  // The cache that contains all the promise apps in the system.
  std::unique_ptr<apps::PromiseAppRegistryCache> promise_app_registry_cache_;

  // Retrieves information from the Almanac Promise App API about the
  // packages being installed.
  std::unique_ptr<PromiseAppAlmanacConnector> promise_app_almanac_connector_;

  // Cache that contains all promise app icons.
  std::unique_ptr<apps::PromiseAppIconCache> promise_app_icon_cache_;

  // Fetches images from a given URL.
  std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;

  raw_ptr<apps::AppRegistryCache> app_registry_cache_;

  // Keeps track of how many icon downloads we are waiting on for each promise
  // app. When all downloads are completed, we can proceed to set (or not set)
  // the promise app as ready to show to the user.
  std::map<PackageId, int> pending_download_count_;

  base::ScopedObservation<apps::AppRegistryCache,
                          apps::AppRegistryCache::Observer>
      app_registry_cache_observation_{this};

  bool skip_almanac_for_testing_ = false;

  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<PromiseAppService> weak_ptr_factory_{this};
};

}  // namespace apps

#endif  // CHROME_BROWSER_APPS_APP_SERVICE_PROMISE_APPS_PROMISE_APP_SERVICE_H_