1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
ash / wallpaper / online_wallpaper_manager.cc [blame]
// 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/online_wallpaper_manager.h"
#include "ash/public/cpp/image_util.h"
#include "ash/public/cpp/wallpaper/online_wallpaper_variant.h"
#include "ash/shell.h"
#include "ash/wallpaper/wallpaper_constants.h"
#include "ash/wallpaper/wallpaper_image_downloader.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_file_utils.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_resizer.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_resolution.h"
#include "base/barrier_closure.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "components/account_id/account_id.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_util.h"
namespace ash {
OnlineWallpaperManager::OnlineWallpaperManager(
WallpaperImageDownloader* wallpaper_image_downloader,
WallpaperFileManager* wallpaper_file_manager)
: wallpaper_image_downloader_(wallpaper_image_downloader),
wallpaper_file_manager_(wallpaper_file_manager) {}
OnlineWallpaperManager::~OnlineWallpaperManager() = default;
void OnlineWallpaperManager::GetOnlineWallpaper(
const base::FilePath& wallpaper_dir,
const AccountId& account_id,
const WallpaperInfo& wallpaper_info,
LoadOnlineWallpaperCallback callback) {
auto on_load = base::BindOnce(
&OnlineWallpaperManager::OnLoadExistingOnlineWallpaperComplete,
weak_factory_.GetWeakPtr(), wallpaper_dir, account_id, wallpaper_info,
std::move(callback));
wallpaper_file_manager_->LoadWallpaper(wallpaper_info.type, wallpaper_dir,
wallpaper_info.location,
std::move(on_load));
}
void OnlineWallpaperManager::OnLoadExistingOnlineWallpaperComplete(
const base::FilePath& wallpaper_dir,
const AccountId& account_id,
const WallpaperInfo& wallpaper_info,
LoadOnlineWallpaperCallback callback,
const gfx::ImageSkia& image) {
DCHECK(callback);
if (image.isNull()) {
DownloadAndSaveAllVariants(wallpaper_dir, account_id, wallpaper_info,
std::move(callback));
} else {
std::move(callback).Run(image);
}
}
void OnlineWallpaperManager::DownloadAndSaveAllVariants(
const base::FilePath& wallpaper_dir,
const AccountId& account_id,
const WallpaperInfo& wallpaper_info,
LoadOnlineWallpaperCallback callback) {
std::vector<OnlineWallpaperVariant> variants = wallpaper_info.variants;
if (variants.empty()) {
// `variants` can be empty for users who have just migrated from the old
// wallpaper picker to the new one.
//
// OnlineWallpaperVariant's `asset_id` and `type` are not actually used in
// this function, so they can have dummy values here.
variants.emplace_back(/*asset_id=*/0, GURL(wallpaper_info.location),
backdrop::Image::IMAGE_TYPE_UNKNOWN);
}
// There's only one variant that is actually needed to fulfill the immediate
// request. However, it's important that all of the other variants are
// available as well (ex: the user picks a wallpaper and toggles between D/L
// modes to see what it looks like). As such, the whole operation is
// considered a failure unless all variants are downloaded (otherwise the
// feature is confusing as it would advertise multiple variants but only
// have one).
auto downloads_result = std::make_unique<VariantsDownloadResult>();
auto* downloads_result_ptr = downloads_result.get();
auto on_all_variants_downloaded = base::BarrierClosure(
variants.size(),
base::BindOnce(&OnlineWallpaperManager::OnAllVariantsDownloaded,
weak_factory_.GetWeakPtr(), std::move(downloads_result),
std::move(callback)));
for (const OnlineWallpaperVariant& variant : variants) {
wallpaper_image_downloader_->DownloadBackdropImage(
variant.raw_url, account_id,
base::BindOnce(
&OnlineWallpaperManager::OnVariantDownloaded,
weak_factory_.GetWeakPtr(), wallpaper_info.type, wallpaper_dir,
variant.raw_url, wallpaper_info.layout,
/*is_target_variant=*/wallpaper_info.location ==
variant.raw_url.spec(),
// Since `downloads_result`'s lifetime matches the
// OnAllVariantsDownloaded() callback, and OnAllVariantsDownloaded()
// is guaranteed to be run after OnVariantDownloaded(), there's no
// possibility of use-after-free.
base::Unretained(downloads_result_ptr),
on_all_variants_downloaded));
}
}
void OnlineWallpaperManager::OnAllVariantsDownloaded(
std::unique_ptr<VariantsDownloadResult> downloads_result,
LoadOnlineWallpaperCallback callback) {
DCHECK(downloads_result);
// Due to the order of variants being downloaded, `target_variant` may have
// been set when others fail to download. To ensure it's all or nothing, we
// need to reset it so the operation is considered a failure.
if (downloads_result->any_downloads_failed) {
downloads_result->target_variant = gfx::ImageSkia();
}
std::move(callback).Run(std::move(downloads_result->target_variant));
}
void OnlineWallpaperManager::OnVariantDownloaded(
WallpaperType type,
const base::FilePath& wallpaper_dir,
const GURL& variant_url,
WallpaperLayout layout,
bool is_target_variant,
VariantsDownloadResult* downloads_result,
base::RepeatingClosure on_done,
const gfx::ImageSkia& image) {
DCHECK(downloads_result);
if (image.isNull()) {
LOG(WARNING) << "Image download failed";
downloads_result->any_downloads_failed = true;
std::move(on_done).Run();
return;
}
if (is_target_variant) {
downloads_result->target_variant = image;
}
// Using wallpaper_file_manager_->SaveWallpaperToDisk() to post a task of
// saving the image to disk via `blocking_task_runner_` to ensure the
// operation order is maintained. It is important this task is executed before
// loading the preview image to make sure the files have been saved on disk.
wallpaper_file_manager_->SaveWallpaperToDisk(
type, wallpaper_dir, variant_url.ExtractFileName(), layout, image);
std::move(on_done).Run();
}
} // namespace ash