chromium/ash/wallpaper/wallpaper_image_downloader.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 "ash/wallpaper/wallpaper_image_downloader.h"

#include <optional>
#include <string>

#include "ash/public/cpp/image_downloader.h"
#include "ash/public/cpp/wallpaper/wallpaper_types.h"
#include "base/functional/callback.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "components/account_id/account_id.h"
#include "net/http/http_request_headers.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"

namespace ash {

namespace {

constexpr net::NetworkTrafficAnnotationTag
    kDownloadGooglePhotoTrafficAnnotation =
        net::DefineNetworkTrafficAnnotation("wallpaper_download_google_photo",
                                            R"(
      semantics {
        sender: "ChromeOS Wallpaper Image Downloader"
        description:
          "When the user selects a photo from their Google Photos collection, "
          "the image must be downloaded at a high enough resolution to display "
          "as a wallpaper. This request fetches that image."
        trigger: "When the user selects a Google Photo as their wallpaper, or "
                 "when that selection reaches this device from cross-device "
                 "sync."
        data: "Stored credentials for the user's Google account."
        destination: GOOGLE_OWNED_SERVICE
        internal {
          contacts {
            email: "[email protected]"
          }
        }
        user_data {
          type: ACCESS_TOKEN
        }
        last_reviewed: "2023-03-06"
      }
      policy {
        cookies_allowed: NO
        setting: "The policy if set, controls the wallpaper image and disables "
        "this feature for user."
        chrome_policy {
          WallpaperImage {
            WallpaperImage: "{}"
          }
        }
      })");

constexpr net::NetworkTrafficAnnotationTag
    kDownloadOnlineWallpaperTrafficAnnotation =
        net::DefineNetworkTrafficAnnotation("wallpaper_online_downloader",
                                            R"(
      semantics {
        sender: "ChromeOS Wallpaper Image Downloader"
        description:
          "When the user selects a photo from their desktop wallpaper "
          "collection, the image must be downloaded at a high enough "
          "resolution to display as a wallpaper. This request fetches "
          "that image."
        trigger: "When the user clicks on the wallpaper thumbnail in "
        "the wallpaper collection"
        data: "None. These URLs are publicly accessible."
        destination: GOOGLE_OWNED_SERVICE
        internal {
          contacts {
            email: "[email protected]"
          }
        }
        user_data {
          type: NONE
        }
        last_reviewed: "2023-03-06"
      }
     policy {
        cookies_allowed: NO
        setting: "The policy if set, controls the wallpaper image and disables "
        "this feature for user."
        chrome_policy {
          WallpaperImage {
            WallpaperImage: "{}"
          }
        }
      })");

GURL AddDimensionsToGooglePhotosURL(GURL url) {
  // Add a string with size data to the URL to make sure we get back the correct
  // resolution image, within reason and maintaining aspect ratio. See:
  // https://developers.google.com/photos/library/guides/access-media-items
  return GURL(base::StringPrintf("%s=w%d-h%d", url.spec().c_str(),
                                 kLargeWallpaperMaxWidth,
                                 kLargeWallpaperMaxHeight));
}

// Returns a suffix to be appended to the base url of Backdrop (online)
// wallpapers.
std::string GetBackdropWallpaperSuffix() {
  // TODO(b/186807814) handle different display resolutions better.
  // FIFE url is used for Backdrop wallpapers and the desired image size should
  // be specified. Currently we are using two times the display size. This is
  // determined by trial and error and is subject to change.
  gfx::Size display_size =
      display::Screen::GetScreen()->GetPrimaryDisplay().size();
  return "=w" + base::NumberToString(
                    2 * std::max(display_size.width(), display_size.height()));
}

}  // namespace

WallpaperImageDownloaderImpl::WallpaperImageDownloaderImpl() = default;

WallpaperImageDownloaderImpl::~WallpaperImageDownloaderImpl() = default;

void WallpaperImageDownloaderImpl::DownloadGooglePhotosImage(
    const GURL& url,
    const AccountId& account_id,
    const std::optional<std::string>& access_token,
    ImageDownloader::DownloadCallback callback) const {
  GURL url_with_dimensions = AddDimensionsToGooglePhotosURL(url);

  net::HttpRequestHeaders headers;
  if (access_token.has_value()) {
    headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
                      "Bearer " + access_token.value());
  }
  ImageDownloader::Get()->Download(url_with_dimensions,
                                   kDownloadGooglePhotoTrafficAnnotation,
                                   account_id, headers, std::move(callback));
}

void WallpaperImageDownloaderImpl::DownloadBackdropImage(
    const GURL& url,
    const AccountId& account_id,
    ImageDownloader::DownloadCallback callback) const {
  ImageDownloader::Get()->Download(
      GURL(url.spec() + GetBackdropWallpaperSuffix()),
      kDownloadOnlineWallpaperTrafficAnnotation, account_id,
      std::move(callback));
}

}  // namespace ash