#include "ash/wallpaper/wallpaper_file_manager.h"
#include <string>
#include "ash/public/cpp/image_util.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller.h"
#include "ash/public/cpp/wallpaper/wallpaper_types.h"
#include "ash/wallpaper/wallpaper_constants.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_file_utils.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/thread_pool.h"
#include "ui/gfx/image/image.h"
namespace ash {
namespace {
std::string GetOnlineWallpaperFileName(const std::string& file_name,
const WallpaperResolution resolution) {
if (resolution == WallpaperResolution::kSmall) {
return base::FilePath(file_name)
.InsertBeforeExtension(wallpaper_constants::kSmallWallpaperSuffix)
.value();
}
return file_name;
}
base::FilePath GetExistingWallpaperPath(const WallpaperType type,
const base::FilePath& wallpaper_dir,
const std::string& location) {
base::FilePath wallpaper_path;
if (IsOnlineWallpaper(type)) {
wallpaper_path = GetOnlineWallpaperFilePath(wallpaper_dir, GURL(location),
GetAppropriateResolution());
if (base::PathExists(wallpaper_path)) {
return wallpaper_path;
}
wallpaper_path = GetOnlineWallpaperFilePath(wallpaper_dir, GURL(location),
WallpaperResolution::kLarge);
if (base::PathExists(wallpaper_path)) {
return wallpaper_path;
}
}
wallpaper_path = wallpaper_dir.Append(location);
if (type == WallpaperType::kSeaPen) {
wallpaper_path = wallpaper_path.ReplaceExtension(".jpg");
}
if (!base::PathExists(wallpaper_path)) {
return base::FilePath();
}
return wallpaper_path;
}
bool DeleteWallpaperPath(const WallpaperType type,
const base::FilePath& wallpaper_dir) {
if (IsOnlineWallpaper(type)) {
return true;
}
return base::DeletePathRecursively(wallpaper_dir);
}
std::string GetStringContent(const base::FilePath& file_path) {
if (file_path.empty() || !base::PathExists(file_path)) {
LOG(WARNING) << "File path is empty or does not exist";
return std::string();
}
std::string result;
if (!base::ReadFileToString(file_path, &result)) {
LOG(WARNING) << "Failed reading file";
result.clear();
}
return result;
}
base::FilePath GetCustomWallpaperDir(const base::FilePath& wallpaper_dir,
const std::string& sub_dir,
const std::string& wallpaper_files_id) {
return wallpaper_dir.Append(sub_dir).Append(wallpaper_files_id);
}
base::FilePath SaveWallpaperToPath(const WallpaperType type,
const base::FilePath& wallpaper_dir,
const std::string& file_name,
const WallpaperLayout layout,
const gfx::ImageSkia image,
const int resized_width = 0,
const int resized_height = 0) {
const base::FilePath file_path = wallpaper_dir.Append(file_name);
if (!DeleteWallpaperPath(type, wallpaper_dir)) {
LOG(ERROR) << "Failed to delete wallpaper path.";
return base::FilePath();
};
CreateDirectoryAndLogError(wallpaper_dir);
const bool success = ResizeAndSaveWallpaper(
image, file_path, layout,
{resized_width == 0 ? image.width() : resized_width,
resized_height == 0 ? image.height() : resized_height});
return success ? file_path : base::FilePath();
}
base::FilePath SaveWallpaperPerType(const WallpaperType type,
const base::FilePath& wallpaper_dir,
const std::string& wallpaper_files_id,
const std::string& file_name,
const WallpaperLayout layout,
const gfx::ImageSkia& image) {
switch (type) {
case WallpaperType::kOnline:
case WallpaperType::kDaily: {
const std::string small_wallpaper_file_name =
GetOnlineWallpaperFileName(file_name, WallpaperResolution::kSmall);
SaveWallpaperToPath(type, wallpaper_dir, small_wallpaper_file_name,
WALLPAPER_LAYOUT_CENTER_CROPPED, image,
kSmallWallpaperMaxWidth, kSmallWallpaperMaxHeight);
return SaveWallpaperToPath(type, wallpaper_dir, file_name, layout, image);
}
case WallpaperType::kCustomized:
case WallpaperType::kPolicy: {
CHECK(!wallpaper_files_id.empty());
SaveWallpaperToPath(
type,
GetCustomWallpaperDir(wallpaper_dir, kSmallWallpaperSubDir,
wallpaper_files_id),
file_name, layout, image, kSmallWallpaperMaxWidth,
kSmallWallpaperMaxHeight);
SaveWallpaperToPath(
type,
GetCustomWallpaperDir(wallpaper_dir, kLargeWallpaperSubDir,
wallpaper_files_id),
file_name, layout, image, kLargeWallpaperMaxWidth,
kLargeWallpaperMaxHeight);
return SaveWallpaperToPath(
type,
GetCustomWallpaperDir(wallpaper_dir, kOriginalWallpaperSubDir,
wallpaper_files_id),
file_name, WALLPAPER_LAYOUT_STRETCH, image);
}
case WallpaperType::kOnceGooglePhotos:
case WallpaperType::kDailyGooglePhotos:
case WallpaperType::kSeaPen:
return SaveWallpaperToPath(type, wallpaper_dir, file_name, layout, image);
default:
NOTREACHED() << "Invalid wallpaper type.";
}
}
scoped_refptr<base::RefCountedMemory> ReadFile(
const base::FilePath& file_path) {
const std::string data = GetStringContent(file_path);
if (data.empty()) {
return nullptr;
}
return base::MakeRefCounted<base::RefCountedString>(std::move(data));
}
}
base::FilePath GetOnlineWallpaperFilePath(
const base::FilePath& wallpaper_dir,
const GURL& url,
const WallpaperResolution resolution) {
CHECK(!wallpaper_dir.empty());
return wallpaper_dir.Append(
GetOnlineWallpaperFileName(url.ExtractFileName(), resolution));
}
WallpaperFileManager::WallpaperFileManager()
: blocking_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) {}
WallpaperFileManager::~WallpaperFileManager() = default;
void WallpaperFileManager::LoadWallpaper(const WallpaperType type,
const base::FilePath& wallpaper_dir,
const std::string& location,
LoadWallpaperCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
blocking_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&GetExistingWallpaperPath, type, wallpaper_dir, location),
base::BindOnce(&WallpaperFileManager::LoadFromDisk,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void WallpaperFileManager::LoadOnlineWallpaperPreview(
const base::FilePath& wallpaper_dir,
const GURL& url,
LoadPreviewImageCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::FilePath& preview_image_path = GetOnlineWallpaperFilePath(
wallpaper_dir, url, GetAppropriateResolution());
blocking_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(&ReadFile, preview_image_path),
std::move(callback));
}
void WallpaperFileManager::SaveWallpaperToDisk(
const WallpaperType type,
const base::FilePath& wallpaper_dir,
const std::string& file_name,
const WallpaperLayout layout,
const gfx::ImageSkia& image,
SaveWallpaperCallback callback,
const std::string& wallpaper_files_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (image.isNull()) {
std::move(callback).Run(base::FilePath());
return;
}
image.EnsureRepsForSupportedScales();
gfx::ImageSkia deep_copy(image.DeepCopy());
blocking_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&SaveWallpaperPerType, type, wallpaper_dir,
wallpaper_files_id, file_name, layout, deep_copy),
std::move(callback));
}
void WallpaperFileManager::LoadFromDisk(LoadWallpaperCallback callback,
const base::FilePath& file_path) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (file_path.empty()) {
std::move(callback).Run(gfx::ImageSkia());
return;
}
image_util::DecodeImageFile(std::move(callback), file_path);
}
}