chromium/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_wallpaper_provider_impl.h

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

#ifndef CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_PERSONALIZATION_APP_PERSONALIZATION_APP_WALLPAPER_PROVIDER_IMPL_H_
#define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_PERSONALIZATION_APP_PERSONALIZATION_APP_WALLPAPER_PROVIDER_IMPL_H_

#include <stdint.h>

#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>

#include "ash/public/cpp/wallpaper/wallpaper_controller.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
#include "ash/public/cpp/wallpaper/wallpaper_info.h"
#include "ash/public/cpp/wallpaper/wallpaper_types.h"
#include "ash/webui/common/mojom/sea_pen.mojom-forward.h"
#include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
#include "ash/webui/personalization_app/personalization_app_wallpaper_provider.h"
#include "base/files/file.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/wallpaper_handlers/wallpaper_fetcher_delegate.h"
#include "content/public/browser/web_ui_data_source.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"

namespace ash {
class ThumbnailLoader;
}  // namespace ash

namespace backdrop {
class Collection;
class Image;
}  // namespace backdrop

namespace content {
class WebUI;
}  // namespace content

namespace wallpaper_handlers {
class BackdropCollectionInfoFetcher;
class WallpaperFetcherDelegate;
class BackdropImageInfoFetcher;
class GooglePhotosAlbumsFetcher;
class GooglePhotosSharedAlbumsFetcher;
class GooglePhotosEnabledFetcher;
class GooglePhotosPhotosFetcher;
}  // namespace wallpaper_handlers

class Profile;

namespace ash::personalization_app {

// Implemented in //chrome because this relies on chrome |wallpaper_handlers|
// code.
class PersonalizationAppWallpaperProviderImpl
    : public PersonalizationAppWallpaperProvider,
      ash::WallpaperControllerObserver {
 public:
  PersonalizationAppWallpaperProviderImpl(
      content::WebUI* web_ui,
      std::unique_ptr<wallpaper_handlers::WallpaperFetcherDelegate>
          wallpaper_fetcher_delegate);

  PersonalizationAppWallpaperProviderImpl(
      const PersonalizationAppWallpaperProviderImpl&) = delete;
  PersonalizationAppWallpaperProviderImpl& operator=(
      const PersonalizationAppWallpaperProviderImpl&) = delete;

  ~PersonalizationAppWallpaperProviderImpl() override;

  // PersonalizationAppWallpaperProvider:
  // |BindInterface| may be called multiple times, for example if the user
  // presses Ctrl+Shift+R while on the personalization app.
  void BindInterface(
      mojo::PendingReceiver<ash::personalization_app::mojom::WallpaperProvider>
          receiver) override;

  void GetWallpaperAsJpegBytes(
      content::WebUIDataSource::GotDataCallback callback) override;

  // Not all users can see google photos. Requires a gaia account to be able to
  // fetch photos.
  bool IsEligibleForGooglePhotos() override;

  // ash::personalization_app::mojom::WallpaperProvider:

  // Configure the window to be transparent so that the user can trigger a "full
  // screen preview" mode. This allows the user to see through the app window to
  // see the chosen wallpaper. This is safe to call multiple times in a row.
  void MakeTransparent() override;

  // Configure the window to be opaque so that after exiting the "full screen
  // preview" mode, the transparent background will be reversed. This is safe
  // to call multiple times in a row.
  void MakeOpaque() override;

  void FetchCollections(FetchCollectionsCallback callback) override;

  void FetchImagesForCollection(
      const std::string& collection_id,
      FetchImagesForCollectionCallback callback) override;

  void FetchGooglePhotosAlbums(
      const std::optional<std::string>& resume_token,
      FetchGooglePhotosAlbumsCallback callback) override;

  void FetchGooglePhotosSharedAlbums(
      const std::optional<std::string>& resume_token,
      FetchGooglePhotosAlbumsCallback callback) override;

  void FetchGooglePhotosEnabled(
      FetchGooglePhotosEnabledCallback callback) override;

  void FetchGooglePhotosPhotos(
      const std::optional<std::string>& item_id,
      const std::optional<std::string>& album_id,
      const std::optional<std::string>& resume_token,
      FetchGooglePhotosPhotosCallback callback) override;

  void GetDefaultImageThumbnail(
      GetDefaultImageThumbnailCallback callback) override;

  void GetLocalImages(GetLocalImagesCallback callback) override;

  void GetLocalImageThumbnail(const base::FilePath& file_path,
                              GetLocalImageThumbnailCallback callback) override;

  void SetWallpaperObserver(
      mojo::PendingRemote<ash::personalization_app::mojom::WallpaperObserver>
          observer) override;

  // ash::WallpaperControllerObserver:
  void OnWallpaperResized() override;

  // ash::WallpaperControllerObserver:
  void OnWallpaperPreviewEnded() override;

  // ash::personalization_app::mojom::WallpaperProvider:
  void SelectWallpaper(uint64_t unit_id,
                       bool preview_mode,
                       SelectWallpaperCallback callback) override;

  void SelectDefaultImage(SelectDefaultImageCallback callback) override;

  void SelectLocalImage(const base::FilePath& path,
                        ash::WallpaperLayout layout,
                        bool preview_mode,
                        SelectLocalImageCallback callback) override;

  void SelectGooglePhotosPhoto(
      const std::string& id,
      ash::WallpaperLayout layout,
      bool preview_mode,
      SelectGooglePhotosPhotoCallback callback) override;

  void SelectGooglePhotosAlbum(
      const std::string& album_id,
      SelectGooglePhotosAlbumCallback callback) override;

  void GetGooglePhotosDailyRefreshAlbumId(
      GetGooglePhotosDailyRefreshAlbumIdCallback callback) override;

  void SetCurrentWallpaperLayout(ash::WallpaperLayout layout) override;

  void SetDailyRefreshCollectionId(
      const std::string& collection_id,
      SetDailyRefreshCollectionIdCallback callback) override;

  void GetDailyRefreshCollectionId(
      GetDailyRefreshCollectionIdCallback callback) override;

  void UpdateDailyRefreshWallpaper(
      UpdateDailyRefreshWallpaperCallback callback) override;

  void IsInTabletMode(IsInTabletModeCallback callback) override;

  void ConfirmPreviewWallpaper() override;

  void CancelPreviewWallpaper() override;

  void ShouldShowTimeOfDayWallpaperDialog(
      ShouldShowTimeOfDayWallpaperDialogCallback callback) override;

  wallpaper_handlers::GooglePhotosAlbumsFetcher*
  GetOrCreateGooglePhotosAlbumsFetcher();

  wallpaper_handlers::GooglePhotosSharedAlbumsFetcher*
  GetOrCreateGooglePhotosSharedAlbumsFetcher();

  wallpaper_handlers::GooglePhotosEnabledFetcher*
  GetOrCreateGooglePhotosEnabledFetcher();

  wallpaper_handlers::GooglePhotosPhotosFetcher*
  GetOrCreateGooglePhotosPhotosFetcher();

 private:
  friend class PersonalizationAppWallpaperProviderImplTest;
  friend class PersonalizationAppWallpaperProviderImplGooglePhotosTest;

  void OnFetchCollections(bool success,
                          const std::vector<backdrop::Collection>& collections);

  void OnFetchCollectionImages(
      FetchImagesForCollectionCallback callback,
      std::unique_ptr<wallpaper_handlers::BackdropImageInfoFetcher> fetcher,
      bool success,
      const std::string& collection_id,
      const std::vector<backdrop::Image>& images);

  void OnFetchGooglePhotosEnabled(
      FetchGooglePhotosEnabledCallback callback,
      ash::personalization_app::mojom::GooglePhotosEnablementState state);

  void OnFetchGooglePhotosPhotos(
      std::optional<std::string> album_id,
      FetchGooglePhotosPhotosCallback callback,
      mojo::StructPtr<mojom::FetchGooglePhotosPhotosResponse> response);

  void OnGetDefaultImage(GetDefaultImageThumbnailCallback callback,
                         const gfx::ImageSkia& image);

  void OnGetLocalImages(GetLocalImagesCallback callback,
                        const std::vector<base::FilePath>& images);

  void OnGetLocalImageThumbnail(GetLocalImageThumbnailCallback callback,
                                const SkBitmap* bitmap,
                                base::File::Error error);

  // Called after attempting to select an online wallpaper. Will be dropped if
  // new requests come in.
  void OnOnlineWallpaperSelected(bool success);

  // Called after attempting to select a Google Photos wallpaper. Will be
  // dropped if new requests come in.
  void OnGooglePhotosWallpaperSelected(bool success);

  // Called after attempting to select a local image. Will be dropped if new
  // requests come in.
  void OnLocalImageSelected(bool success);

  // Called after attempting to update a daily refresh wallpaper. Will be
  // dropped if new requests come in.
  void OnDailyRefreshWallpaperUpdated(bool success);

  // Called after forching the current wallpaper image to refresh as part of
  // toggling on daily refresh mode.
  void OnDailyRefreshWallpaperForced(bool success);

  void FindAttribution(
      const ash::WallpaperInfo& info,
      const std::optional<std::vector<backdrop::Collection>>& collections);

  void FindImageMetadataInCollection(
      const ash::WallpaperInfo& info,
      std::size_t current_index,
      const std::optional<std::vector<backdrop::Collection>>& collections,
      bool success,
      const std::string& collection_id,
      const std::vector<backdrop::Image>& images);

  void FindSeaPenWallpaperAttribution(uint32_t id);

  void SendSeaPenWallpaperAttribution(
      uint32_t id,
      const gfx::ImageSkia& image,
      mojom::RecentSeaPenImageInfoPtr sea_pen_metadata);

  void SendGooglePhotosAttribution(
      const ash::WallpaperInfo& info,
      mojo::StructPtr<ash::personalization_app::mojom::GooglePhotosPhoto> photo,
      bool success);

  // Called when the user sets an image, or cancels/confirms preview wallpaper.
  // If a new image is set in preview mode, will minimize all windows except the
  // wallpaper SWA. When canceling or confirming preview mode, will restore the
  // minimized windows to their previous state.
  void SetMinimizedWindowStateForPreview(bool preview_mode);

  void NotifyAttributionChanged(
      ash::personalization_app::mojom::CurrentAttributionPtr attribution);

  void NotifyWallpaperChanged(
      ash::personalization_app::mojom::CurrentWallpaperPtr current_wallpaper);

  std::unique_ptr<wallpaper_handlers::BackdropCollectionInfoFetcher>
      wallpaper_collection_info_fetcher_;
  std::vector<FetchCollectionsCallback> pending_collections_callbacks_;

  std::unique_ptr<wallpaper_handlers::BackdropImageInfoFetcher>
      wallpaper_attribution_info_fetcher_;

  // Fetches the Google Photos albums the user has created. Constructed lazily
  // at the time of the first request and then persists for the rest of the
  // delegate's lifetime, unless preemptively or subsequently replaced by a mock
  // in a test.
  std::unique_ptr<wallpaper_handlers::GooglePhotosAlbumsFetcher>
      google_photos_albums_fetcher_;

  // Fetches the Google Photos albums shared with the user. Constructed lazily
  // at the time of the first request and then persists for the rest of the
  // delegate's lifetime, unless preemptively or subsequently replaced by a mock
  // in a test.
  std::unique_ptr<wallpaper_handlers::GooglePhotosSharedAlbumsFetcher>
      google_photos_shared_albums_fetcher_;

  // Fetches the state of the user's permission to access Google Photos data.
  // Constructed lazily at the time of the first request and then persists for
  // the rest of the delegate's lifetime, unless preemptively or subsequently
  // replaced by a mock in a test.
  std::unique_ptr<wallpaper_handlers::GooglePhotosEnabledFetcher>
      google_photos_enabled_fetcher_;

  // Fetches visible photos from the user's Google Photos library. Constructed
  // lazily at the time of the first request and then persists for the rest of
  // the delegate's lifetime, unless preemptively or subsequently replaced by a
  // mock in a test.
  std::unique_ptr<wallpaper_handlers::GooglePhotosPhotosFetcher>
      google_photos_photos_fetcher_;

  // Set to true when an enabled Google Photos enterprise setting is fetched
  // from the server. Attempting to select a Google Photos wallpaper or fetch
  // Google Photos data other than the enterprise setting itself will fail if
  // this value is false.
  bool is_google_photos_enterprise_enabled_ = false;

  SelectWallpaperCallback pending_select_wallpaper_callback_;

  SelectLocalImageCallback pending_select_local_image_callback_;

  SelectGooglePhotosPhotoCallback pending_select_google_photos_photo_callback_;

  base::OnceCallback<void(bool success)> pending_set_daily_refresh_callback_;

  UpdateDailyRefreshWallpaperCallback
      pending_update_daily_refresh_wallpaper_callback_;

  std::unique_ptr<ash::ThumbnailLoader> thumbnail_loader_;

  struct ImageInfo {
    GURL image_url;
    std::string collection_id;
    uint64_t asset_id;
    uint64_t unit_id;
    backdrop::Image::ImageType type;

    ImageInfo(const GURL& in_image_url,
              const std::string& in_collection_id,
              uint64_t in_asset_id,
              uint64_t in_unit_id,
              backdrop::Image::ImageType in_type)
        : image_url(in_image_url),
          collection_id(in_collection_id),
          asset_id(in_asset_id),
          unit_id(in_unit_id),
          type(in_type) {}
  };

  // Stores the mapping of valid image unit_ids and their image variants. This
  // is filled when a user first visits the Wallpaper subpage of Personalization
  // App.
  std::map<uint64_t, std::vector<ImageInfo>> image_unit_id_map_;

  // Stores the mapping of Google Photos album id to its photos' dedup keys.
  // Used to determine whether an album contains the currently selected
  // wallpaper image.
  std::map<std::string, std::set<std::string>> album_id_dedup_key_map_;

  // When local images are fetched, store the valid file paths in the set. This
  // is checked when the SWA requests thumbnail data or sets an image as the
  // user's background.
  std::set<base::FilePath> local_images_;

  const raw_ptr<content::WebUI> web_ui_ = nullptr;

  // Pointer to profile of user that opened personalization SWA. Not owned.
  const raw_ptr<Profile> profile_ = nullptr;

  base::ScopedObservation<ash::WallpaperController,
                          ash::WallpaperControllerObserver>
      wallpaper_controller_observer_{this};

  const std::unique_ptr<wallpaper_handlers::WallpaperFetcherDelegate>
      wallpaper_fetcher_delegate_;

  // Place near bottom of class so this is cleaned up before any pending
  // callbacks are dropped.
  mojo::Receiver<ash::personalization_app::mojom::WallpaperProvider>
      wallpaper_receiver_{this};

  mojo::Remote<ash::personalization_app::mojom::WallpaperObserver>
      wallpaper_observer_remote_;

  // Used for interacting with local filesystem.
  base::WeakPtrFactory<PersonalizationAppWallpaperProviderImpl>
      backend_weak_ptr_factory_{this};

  // Used for fetching online image attribution.
  base::WeakPtrFactory<PersonalizationAppWallpaperProviderImpl>
      attribution_weak_ptr_factory_{this};

  // General use other than the specific cases above.
  base::WeakPtrFactory<PersonalizationAppWallpaperProviderImpl>
      weak_ptr_factory_{this};
};

}  // namespace ash::personalization_app

#endif  // CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_PERSONALIZATION_APP_PERSONALIZATION_APP_WALLPAPER_PROVIDER_IMPL_H_