online_wallpaper_variant_info_fetcher.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/wallpaper/online_wallpaper_variant_info_fetcher.h"
  5. #include <algorithm>
  6. #include "ash/public/cpp/wallpaper/online_wallpaper_params.h"
  7. #include "ash/public/cpp/wallpaper/online_wallpaper_variant.h"
  8. #include "ash/public/cpp/wallpaper/wallpaper_controller_client.h"
  9. #include "ash/public/cpp/wallpaper/wallpaper_info.h"
  10. #include "ash/webui/personalization_app/proto/backdrop_wallpaper.pb.h"
  11. #include "base/bind.h"
  12. #include "base/callback.h"
  13. #include "base/logging.h"
  14. #include "base/strings/string_piece.h"
  15. #include "base/threading/sequenced_task_runner_handle.h"
  16. namespace ash {
  17. namespace {
  18. // Convenience alias for ColorMode enum.
  19. using ColorMode = OnlineWallpaperVariantInfoFetcher::ColorMode;
  20. // Checks if the given |variant| is suitable for the current system's color
  21. // mode. Image with type |Image_ImageType_IMAGE_TYPE_UNKNOWN| is not D/L aware
  22. // and should be used regardless of color mode.
  23. bool IsSuitableOnlineWallpaperVariant(const OnlineWallpaperVariant& variant,
  24. ColorMode mode) {
  25. switch (variant.type) {
  26. case backdrop::Image_ImageType_IMAGE_TYPE_UNKNOWN:
  27. return true;
  28. case backdrop::Image_ImageType_IMAGE_TYPE_LIGHT_MODE:
  29. return mode == ColorMode::kLightMode;
  30. case backdrop::Image_ImageType_IMAGE_TYPE_DARK_MODE:
  31. return mode == ColorMode::kDarkMode;
  32. }
  33. }
  34. // Returns a pointer to the first matching variant in |variants| if one
  35. // exists.
  36. const OnlineWallpaperVariant* FirstValidVariant(
  37. const std::vector<OnlineWallpaperVariant>& variants,
  38. ColorMode mode) {
  39. const auto iter = std::find_if(
  40. variants.begin(), variants.end(), [mode](const auto& variant) {
  41. return IsSuitableOnlineWallpaperVariant(variant, mode);
  42. });
  43. if (iter != variants.end())
  44. return &(*iter);
  45. return nullptr;
  46. }
  47. // The filtered results from a set of backdrop::Images for a given |asset_id|
  48. // and |mode| value.
  49. class VariantMatches {
  50. public:
  51. VariantMatches(VariantMatches&&) = default;
  52. VariantMatches(const VariantMatches&) = delete;
  53. VariantMatches& operator=(const VariantMatches&) = delete;
  54. ~VariantMatches() = default;
  55. // Filters |images| to only the entries that match |asset_id| and
  56. // |mode|.
  57. static absl::optional<VariantMatches> FromImages(
  58. uint64_t asset_id,
  59. ColorMode mode,
  60. const std::vector<backdrop::Image>& images) {
  61. // Find the exact image in the |images| collection.
  62. auto image_iter = std::find_if(images.begin(), images.end(),
  63. [asset_id](const backdrop::Image& image) {
  64. return asset_id == image.asset_id();
  65. });
  66. if (image_iter == images.end())
  67. return absl::nullopt;
  68. uint64_t unit_id = image_iter->unit_id();
  69. std::vector<OnlineWallpaperVariant> variants;
  70. for (const auto& image : images) {
  71. if (image.unit_id() == unit_id) {
  72. variants.emplace_back(image.asset_id(), GURL(image.image_url()),
  73. image.has_image_type()
  74. ? image.image_type()
  75. : backdrop::Image::IMAGE_TYPE_UNKNOWN);
  76. }
  77. }
  78. const OnlineWallpaperVariant* variant = FirstValidVariant(variants, mode);
  79. if (!variant) {
  80. // At least one usable variant must be found to use this set of images.
  81. return absl::nullopt;
  82. }
  83. return VariantMatches(unit_id, std::move(variants), *variant);
  84. }
  85. // The unit id of the Variant that matched |asset_id| and |mode|.
  86. const uint64_t unit_id;
  87. // The set of images that are appropriate for |asset_id| and
  88. // |mode|.
  89. const std::vector<OnlineWallpaperVariant> variants;
  90. // The first instance from |variants| that matches |asset_id| and
  91. // |mode|.
  92. const OnlineWallpaperVariant first_match;
  93. private:
  94. VariantMatches(uint64_t unit_id_in,
  95. std::vector<OnlineWallpaperVariant>&& variants_in,
  96. const OnlineWallpaperVariant& first_match_in)
  97. : unit_id(unit_id_in),
  98. variants(variants_in),
  99. first_match(first_match_in) {
  100. DCHECK_EQ(std::count(variants.begin(), variants.end(), first_match), 1);
  101. }
  102. };
  103. bool IsDaily(const WallpaperInfo& info) {
  104. return info.type == WallpaperType::kDaily;
  105. }
  106. } // namespace
  107. OnlineWallpaperVariantInfoFetcher::OnlineWallpaperRequest::
  108. OnlineWallpaperRequest(const AccountId& account_id_in,
  109. const std::string& collection_id_in,
  110. WallpaperLayout layout_in,
  111. bool daily_refresh_enabled_in,
  112. ColorMode mode_in)
  113. : account_id(account_id_in),
  114. collection_id(collection_id_in),
  115. layout(layout_in),
  116. daily_refresh_enabled(daily_refresh_enabled_in),
  117. mode(mode_in) {}
  118. OnlineWallpaperVariantInfoFetcher::OnlineWallpaperRequest::
  119. ~OnlineWallpaperRequest() = default;
  120. OnlineWallpaperVariantInfoFetcher::OnlineWallpaperVariantInfoFetcher() =
  121. default;
  122. OnlineWallpaperVariantInfoFetcher::~OnlineWallpaperVariantInfoFetcher() =
  123. default;
  124. void OnlineWallpaperVariantInfoFetcher::SetClient(
  125. WallpaperControllerClient* client) {
  126. wallpaper_controller_client_ = client;
  127. }
  128. void OnlineWallpaperVariantInfoFetcher::FetchOnlineWallpaper(
  129. const AccountId& account_id,
  130. const WallpaperInfo& info,
  131. ColorMode mode,
  132. FetchParamsCallback callback) {
  133. DCHECK(info.type == WallpaperType::kDaily ||
  134. info.type == WallpaperType::kOnline);
  135. DCHECK(wallpaper_controller_client_);
  136. if (info.unit_id.has_value() && !info.variants.empty()) {
  137. // |info| already has all of the data we need.
  138. const OnlineWallpaperVariant* variant =
  139. FirstValidVariant(info.variants, mode);
  140. if (!variant) {
  141. NOTREACHED() << "No suitable wallpaper for "
  142. << (mode == ColorMode::kDarkMode ? "dark" : "lite")
  143. << " mode in collection";
  144. base::SequencedTaskRunnerHandle::Get()->PostTask(
  145. FROM_HERE, base::BindOnce(std::move(callback), absl::nullopt));
  146. return;
  147. }
  148. base::SequencedTaskRunnerHandle::Get()->PostTask(
  149. FROM_HERE,
  150. base::BindOnce(
  151. std::move(callback),
  152. OnlineWallpaperParams{account_id, variant->asset_id,
  153. GURL(variant->raw_url), info.collection_id,
  154. info.layout, /*preview_mode=*/false,
  155. /*from_user=*/false, IsDaily(info),
  156. info.unit_id, info.variants}));
  157. return;
  158. }
  159. // For requests from existing WallpaperInfo, asset_id is always populated.
  160. DCHECK(info.asset_id.has_value());
  161. bool daily = IsDaily(info);
  162. auto request = std::make_unique<OnlineWallpaperRequest>(
  163. account_id, info.collection_id, info.layout, daily, mode);
  164. auto collection_id = request->collection_id;
  165. wallpaper_controller_client_->FetchImagesForCollection(
  166. collection_id,
  167. base::BindOnce(
  168. &OnlineWallpaperVariantInfoFetcher::FindAndSetOnlineWallpaperVariants,
  169. weak_factory_.GetWeakPtr(), std::move(request), *info.asset_id,
  170. std::move(callback)));
  171. }
  172. bool OnlineWallpaperVariantInfoFetcher::FetchDailyWallpaper(
  173. const AccountId& account_id,
  174. const WallpaperInfo& info,
  175. ColorMode mode,
  176. FetchParamsCallback callback) {
  177. DCHECK(IsDaily(info));
  178. // We might not have a client yet.
  179. if (!wallpaper_controller_client_)
  180. return false;
  181. bool daily = true; // This is always a a daily wallpaper.
  182. auto request = std::make_unique<OnlineWallpaperRequest>(
  183. account_id, info.collection_id, info.layout, daily, mode);
  184. wallpaper_controller_client_->FetchDailyRefreshWallpaper(
  185. info.collection_id,
  186. base::BindOnce(&OnlineWallpaperVariantInfoFetcher::OnSingleFetch,
  187. weak_factory_.GetWeakPtr(), std::move(request),
  188. std::move(callback)));
  189. return true;
  190. }
  191. void OnlineWallpaperVariantInfoFetcher::OnSingleFetch(
  192. std::unique_ptr<OnlineWallpaperRequest> request,
  193. FetchParamsCallback callback,
  194. bool success,
  195. const backdrop::Image& image) {
  196. if (!success) {
  197. std::move(callback).Run(absl::nullopt);
  198. return;
  199. }
  200. // If wallpaper_controller_client_ is null, we're shutting down.
  201. if (!wallpaper_controller_client_)
  202. return;
  203. auto collection_id = request->collection_id;
  204. wallpaper_controller_client_->FetchImagesForCollection(
  205. collection_id,
  206. base::BindOnce(
  207. &OnlineWallpaperVariantInfoFetcher::FindAndSetOnlineWallpaperVariants,
  208. weak_factory_.GetWeakPtr(), std::move(request), image.asset_id(),
  209. std::move(callback)));
  210. }
  211. void OnlineWallpaperVariantInfoFetcher::FindAndSetOnlineWallpaperVariants(
  212. std::unique_ptr<OnlineWallpaperRequest> request,
  213. uint64_t asset_id,
  214. FetchParamsCallback callback,
  215. bool success,
  216. const std::vector<backdrop::Image>& images) {
  217. if (!success) {
  218. LOG(WARNING) << "Failed to fetch online wallpapers";
  219. std::move(callback).Run(absl::nullopt);
  220. return;
  221. }
  222. absl::optional<VariantMatches> matches =
  223. VariantMatches::FromImages(asset_id, request->mode, images);
  224. if (!matches) {
  225. LOG(ERROR) << "No valid variants";
  226. std::move(callback).Run(absl::nullopt);
  227. return;
  228. }
  229. const OnlineWallpaperVariant& first_image = matches->first_match;
  230. DCHECK(IsSuitableOnlineWallpaperVariant(first_image, request->mode));
  231. std::move(callback).Run(ash::OnlineWallpaperParams{
  232. request->account_id, first_image.asset_id, first_image.raw_url,
  233. request->collection_id, request->layout, /*preview_mode=*/false,
  234. /*from_user=*/false, request->daily_refresh_enabled, matches->unit_id,
  235. matches->variants});
  236. }
  237. } // namespace ash