#include "ash/wallpaper/wallpaper_controller_impl.h"
#include <algorithm>
#include <optional>
#include <string>
#include <string_view>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_paths.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/login/login_screen_controller.h"
#include "ash/public/cpp/image_downloader.h"
#include "ash/public/cpp/image_util.h"
#include "ash/public/cpp/schedule_enums.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/wallpaper/google_photos_wallpaper_params.h"
#include "ash/public/cpp/wallpaper/online_wallpaper_params.h"
#include "ash/public/cpp/wallpaper/online_wallpaper_variant.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller_client.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
#include "ash/public/cpp/wallpaper/wallpaper_drivefs_delegate.h"
#include "ash/public/cpp/wallpaper/wallpaper_info.h"
#include "ash/public/cpp/wallpaper/wallpaper_types.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/style/dark_light_mode_controller_impl.h"
#include "ash/system/scheduled_feature/scheduled_feature.h"
#include "ash/system/time/time_of_day.h"
#include "ash/wallpaper/online_wallpaper_manager.h"
#include "ash/wallpaper/sea_pen_wallpaper_manager.h"
#include "ash/wallpaper/views/wallpaper_view.h"
#include "ash/wallpaper/views/wallpaper_widget_controller.h"
#include "ash/wallpaper/wallpaper_blur_manager.h"
#include "ash/wallpaper/wallpaper_constants.h"
#include "ash/wallpaper/wallpaper_daily_refresh_scheduler.h"
#include "ash/wallpaper/wallpaper_image_downloader.h"
#include "ash/wallpaper/wallpaper_metrics_manager.h"
#include "ash/wallpaper/wallpaper_pref_manager.h"
#include "ash/wallpaper/wallpaper_utils/sea_pen_metadata_utils.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_calculated_colors.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_color_calculator.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_customization_id.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_ephemeral_user.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_file_utils.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_online_variant_utils.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_resizer.h"
#include "ash/wallpaper/wallpaper_utils/wallpaper_resolution.h"
#include "ash/wallpaper/wallpaper_window_state_manager.h"
#include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
#include "ash/wm/overview/overview_controller.h"
#include "base/barrier_closure.h"
#include "base/check.h"
#include "base/check_is_test.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/types/cxx23_to_underlying.h"
#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
#include "chromeos/ash/components/system/statistics_provider.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/account_id/account_id.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/session_manager_types.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "services/data_decoder/public/mojom/image_decoder.mojom-shared.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/display/screen.h"
#include "ui/display/tablet_state.h"
#include "ui/display/util/display_util.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_util.h"
#include "url/gurl.h"
using color_utils::ColorProfile;
using FilePathCallback = base::OnceCallback<void(const base::FilePath&)>;
namespace ash {
namespace {
std::unique_ptr<WallpaperPrefManager> g_test_pref_manager;
std::unique_ptr<WallpaperImageDownloader> g_test_image_downloader;
constexpr char kPolicyWallpaperFile[] = "policy-controlled.jpeg";
constexpr base::TimeDelta kWallpaperReloadDelay = base::Milliseconds(100);
constexpr base::TimeDelta kCompositorLockTimeout = base::Milliseconds(750);
constexpr SkColor kDefaultWallpaperColor = SK_ColorGRAY;
constexpr SkColor kOobeWallpaperColor = SK_ColorWHITE;
std::string GetCustomWallpaperSubdirForCurrentResolution() {
WallpaperResolution resolution = GetAppropriateResolution();
return resolution == WallpaperResolution::kSmall ? kSmallWallpaperSubDir
: kLargeWallpaperSubDir;
}
gfx::ImageSkia CreateSolidColorWallpaper(SkColor color) {
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(color);
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
}
void DeleteWallpaperInList(std::vector<base::FilePath> file_list) {
for (const base::FilePath& path : file_list) {
if (!base::DeletePathRecursively(path))
LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
}
}
bool IsInKioskMode() {
std::optional<user_manager::UserType> active_user_type =
Shell::Get()->session_controller()->GetUserType();
return active_user_type &&
*active_user_type == user_manager::UserType::kKioskChromeApp;
}
const UserSession* GetActiveUserSession() {
return Shell::Get()->session_controller()->GetUserSession(0);
}
AccountId GetActiveAccountId() {
const UserSession* const session = GetActiveUserSession();
DCHECK(session);
return session->user_info.account_id;
}
bool IsActiveUser(const AccountId& account_id) {
const UserSession* const session = GetActiveUserSession();
return session && session->user_info.account_id == account_id;
}
user_manager::UserType GetUserType(const AccountId& id) {
const UserSession* user_session =
Shell::Get()->session_controller()->GetUserSessionByAccountId(id);
if (!user_session) {
LOG(ERROR) << "Cannot resolve user. Assuming regular. This should only "
"happen in tests";
return user_manager::UserType::kRegular;
}
return user_session->user_info.type;
}
base::FilePath PathWithFallback(const base::FilePath& wallpaper_path,
const base::FilePath& fallback_path) {
if (base::PathExists(wallpaper_path))
return wallpaper_path;
return base::PathExists(fallback_path) ? fallback_path : base::FilePath();
}
scoped_refptr<base::RefCountedMemory> EncodeAndResizeImage(
gfx::ImageSkia image) {
auto resized = WallpaperResizer::GetResizedImage(image,
1024);
std::optional<std::vector<uint8_t>> jpg_buffer =
gfx::JPEG1xEncodedDataFromImage(gfx::Image(resized), 90);
if (jpg_buffer) {
return base::MakeRefCounted<base::RefCountedBytes>(
std::move(jpg_buffer).value());
}
return base::MakeRefCounted<base::RefCountedBytes>(0);
}
std::unique_ptr<WallpaperInfo> CreateOnlineWallpaperInfo(
const OnlineWallpaperParams& params,
const ScheduledFeature& scheduled_feature,
const char* source) {
const OnlineWallpaperVariant* selected_variant = FirstValidVariant(
params.variants, scheduled_feature.current_checkpoint());
if (!selected_variant) {
LOG(ERROR) << "Failed to select online wallpaper variant from " << source;
return nullptr;
}
return std::make_unique<WallpaperInfo>(params, *selected_variant);
}
}
std::unique_ptr<WallpaperControllerImpl> WallpaperControllerImpl::Create(
PrefService* local_state) {
std::unique_ptr<WallpaperPrefManager> pref_manager =
g_test_pref_manager ? std::move(g_test_pref_manager)
: WallpaperPrefManager::Create(local_state);
std::unique_ptr<WallpaperImageDownloader> wallpaper_image_downloader =
g_test_image_downloader
? std::move(g_test_image_downloader)
: std::make_unique<WallpaperImageDownloaderImpl>();
return std::make_unique<WallpaperControllerImpl>(
std::move(pref_manager), std::move(wallpaper_image_downloader));
}
void WallpaperControllerImpl::SetWallpaperPrefManagerForTesting(
std::unique_ptr<WallpaperPrefManager> pref_manager) {
g_test_pref_manager.swap(pref_manager);
}
void WallpaperControllerImpl::SetWallpaperImageDownloaderForTesting(
std::unique_ptr<WallpaperImageDownloader> image_downloader) {
g_test_image_downloader.swap(image_downloader);
}
WallpaperControllerImpl::WallpaperControllerImpl(
std::unique_ptr<WallpaperPrefManager> pref_manager,
std::unique_ptr<WallpaperImageDownloader> image_downloader)
: pref_manager_(std::move(pref_manager)),
blur_manager_(std::make_unique<WallpaperBlurManager>()),
wallpaper_reload_delay_(kWallpaperReloadDelay),
wallpaper_image_downloader_(std::move(image_downloader)),
wallpaper_file_manager_(std::make_unique<WallpaperFileManager>()),
online_wallpaper_manager_(
OnlineWallpaperManager(wallpaper_image_downloader_.get(),
wallpaper_file_manager_.get())),
google_photos_wallpaper_manager_(
GooglePhotosWallpaperManager(wallpaper_image_downloader_.get(),
wallpaper_file_manager_.get())),
sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})) {
Shell::Get()->display_manager()->AddDisplayManagerObserver(this);
Shell::Get()->AddShellObserver(this);
Shell::Get()->login_screen_controller()->data_dispatcher()->AddObserver(this);
theme_observation_.Observe(ui::NativeTheme::GetInstanceForNativeUi());
wallpaper_metrics_manager_ = std::make_unique<WallpaperMetricsManager>();
CHECK(base::PathService::Get(ash::DIR_WALLPAPERS, &wallpapers_dir_));
CHECK(base::PathService::Get(ash::DIR_CUSTOM_WALLPAPERS,
&custom_wallpapers_dir_));
google_photos_wallpapers_dir_ = wallpapers_dir_.Append("google_photos/");
sea_pen_wallpaper_dir_ =
wallpapers_dir_.Append(wallpaper_constants::kSeaPenWallpaperDirName);
pref_manager_observation_.Observe(pref_manager_.get());
SetDevicePolicyWallpaperPath(
pref_manager_->GetDeviceWallpaperImageFilePath());
}
WallpaperControllerImpl::~WallpaperControllerImpl() {
pref_manager_observation_.Reset();
Shell::Get()->display_manager()->RemoveDisplayManagerObserver(this);
Shell::Get()->RemoveShellObserver(this);
}
base::FilePath WallpaperControllerImpl::GetCustomWallpaperPath(
const std::string& sub_dir,
const std::string& wallpaper_files_id,
const std::string& file_name) const {
base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
return custom_wallpaper_path.Append(wallpaper_files_id).Append(file_name);
}
base::FilePath WallpaperControllerImpl::GetCustomWallpaperDir(
const std::string& sub_dir) const {
CHECK(!custom_wallpapers_dir_.empty());
return custom_wallpapers_dir_.Append(sub_dir);
}
SkColor WallpaperControllerImpl::GetKMeanColor() const {
return calculated_colors_ ? calculated_colors_->k_mean_color
: kInvalidWallpaperColor;
}
std::optional<SkColor> WallpaperControllerImpl::GetCachedWallpaperColorForUser(
const AccountId& account_id,
bool should_use_k_means) const {
WallpaperInfo info;
if (!pref_manager_->GetLocalWallpaperInfo(account_id, &info)) {
return {};
}
return should_use_k_means ? pref_manager_->GetCachedKMeanColor(info.location)
: pref_manager_->GetCelebiColor(info.location);
}
gfx::ImageSkia WallpaperControllerImpl::GetWallpaper() const {
return current_wallpaper_ ? current_wallpaper_->image() : gfx::ImageSkia();
}
WallpaperLayout WallpaperControllerImpl::GetWallpaperLayout() const {
return current_wallpaper_ ? current_wallpaper_->wallpaper_info().layout
: NUM_WALLPAPER_LAYOUT;
}
WallpaperType WallpaperControllerImpl::GetWallpaperType() const {
return current_wallpaper_ ? current_wallpaper_->wallpaper_info().type
: WallpaperType::kCount;
}
bool WallpaperControllerImpl::ShouldShowInitialAnimation() {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kFirstExecAfterBoot)) {
return false;
}
if (Shell::Get()->session_controller()->IsActiveUserSessionStarted() ||
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kLoginManager)) {
return false;
}
if (!is_first_wallpaper_)
return false;
return true;
}
bool WallpaperControllerImpl::HasShownAnyWallpaper() const {
return !!current_wallpaper_;
}
void WallpaperControllerImpl::MaybeClosePreviewWallpaper() {
if (!confirm_preview_wallpaper_callback_) {
DCHECK(!reload_preview_wallpaper_callback_);
return;
}
CancelPreviewWallpaper();
}
void WallpaperControllerImpl::ShowWallpaperImage(const gfx::ImageSkia& image,
WallpaperInfo info,
bool preview_mode,
bool is_override) {
if (is_override_wallpaper_ && !is_override) {
return;
}
if (confirm_preview_wallpaper_callback_ && !preview_mode)
return;
if (preview_mode) {
DVLOG(1) << __func__ << " preview_mode=true";
for (auto& observer : observers_)
observer.OnWallpaperPreviewStarted();
}
if (image.width() == 1 && image.height() == 1)
info.layout = WALLPAPER_LAYOUT_STRETCH;
if (info.type == WallpaperType::kOneShot)
info.one_shot_wallpaper = image.DeepCopy();
VLOG(1) << "SetWallpaper: image_id=" << WallpaperResizer::GetImageId(image)
<< " layout=" << info.layout;
if (WallpaperIsAlreadyLoaded(image, true, info.layout)) {
VLOG(1) << "Wallpaper is already loaded";
return;
}
if (color_calculator_) {
color_calculator_.reset();
}
is_first_wallpaper_ = !current_wallpaper_;
current_wallpaper_ = std::make_unique<WallpaperResizer>(
image, GetMaxDisplaySizeInNative(), info);
current_wallpaper_->StartResize(base::BindOnce(
&WallpaperControllerImpl::OnWallpaperResized, base::Unretained(this)));
if (is_first_wallpaper_) {
for (auto& observer : observers_)
observer.OnFirstWallpaperShown();
}
for (auto& observer : observers_)
observer.OnWallpaperChanging();
wallpaper_mode_ = WALLPAPER_IMAGE;
UpdateWallpaperForAllRootWindows(
Shell::Get()->session_controller()->IsUserSessionBlocked());
++wallpaper_count_for_testing_;
for (auto& observer : observers_)
observer.OnWallpaperChanged();
}
void WallpaperControllerImpl::UpdateWallpaperBlurForLockState(bool blur) {
bool changed =
blur_manager_->UpdateWallpaperBlurForLockState(blur, GetWallpaperType());
if (changed) {
for (auto& observer : observers_) {
observer.OnWallpaperBlurChanged();
}
}
}
void WallpaperControllerImpl::RestoreWallpaperBlurForLockState(float blur) {
const WallpaperType wallpaper_type = GetWallpaperType();
if (!blur_manager_->IsBlurAllowedForLockState(wallpaper_type)) {
return;
}
blur_manager_->RestoreWallpaperBlurForLockState(blur, wallpaper_type);
for (auto& observer : observers_) {
observer.OnWallpaperBlurChanged();
}
}
bool WallpaperControllerImpl::ShouldApplyShield() const {
bool needs_shield = false;
if (Shell::Get()->overview_controller()->InOverviewSession()) {
needs_shield = false;
} else if (Shell::Get()->session_controller()->IsUserSessionBlocked()) {
needs_shield = true;
} else if (display::Screen::Get()->InTabletMode() &&
!confirm_preview_wallpaper_callback_) {
needs_shield = true;
}
return needs_shield && (!IsOneShotWallpaper() || allow_shield_for_testing_);
}
bool WallpaperControllerImpl::SetUserWallpaperInfo(const AccountId& account_id,
const WallpaperInfo& info) {
CleanUpBeforeSettingUserWallpaperInfo(account_id, info);
return pref_manager_->SetUserWallpaperInfo(account_id, info);
}
bool WallpaperControllerImpl::SetUserWallpaperInfo(const AccountId& account_id,
bool is_ephemeral,
const WallpaperInfo& info) {
CleanUpBeforeSettingUserWallpaperInfo(account_id, info);
return pref_manager_->SetUserWallpaperInfo(account_id, is_ephemeral, info);
}
bool WallpaperControllerImpl::GetUserWallpaperInfo(const AccountId& account_id,
WallpaperInfo* info) const {
return pref_manager_->GetUserWallpaperInfo(account_id, info);
}
bool WallpaperControllerImpl::GetWallpaperFromCache(const AccountId& account_id,
gfx::ImageSkia* image) {
CustomWallpaperMap::const_iterator it = wallpaper_cache_map_.find(account_id);
if (it != wallpaper_cache_map_.end() && !it->second.second.isNull()) {
*image = it->second.second;
return true;
}
return false;
}
bool WallpaperControllerImpl::GetPathFromCache(const AccountId& account_id,
base::FilePath* path) {
CustomWallpaperMap::const_iterator it = wallpaper_cache_map_.find(account_id);
if (it != wallpaper_cache_map_.end()) {
*path = it->second.first;
return true;
}
return false;
}
void WallpaperControllerImpl::AddFirstWallpaperAnimationEndCallback(
base::OnceClosure callback,
aura::Window* window) {
WallpaperWidgetController* wallpaper_widget_controller =
RootWindowController::ForWindow(window)->wallpaper_widget_controller();
if (!current_wallpaper_ ||
(is_first_wallpaper_ && wallpaper_widget_controller->IsAnimating())) {
wallpaper_widget_controller->AddAnimationEndCallback(std::move(callback));
} else {
std::move(callback).Run();
}
}
void WallpaperControllerImpl::StartDecodeFromPath(
const AccountId& account_id,
const user_manager::UserType user_type,
const WallpaperInfo& info,
bool show_wallpaper,
const base::FilePath& wallpaper_path) {
if (wallpaper_path.empty()) {
wallpaper_cache_map_.erase(account_id);
SetDefaultWallpaperImpl(user_type, show_wallpaper, base::DoNothing());
return;
}
ReadAndDecodeWallpaper(
base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id, wallpaper_path,
info, show_wallpaper),
wallpaper_path);
}
void WallpaperControllerImpl::SetClient(WallpaperControllerClient* client) {
wallpaper_controller_client_ = client;
pref_manager_->SetClient(client);
variant_info_fetcher_.SetClient(client);
google_photos_wallpaper_manager_.SetClient(client);
}
void WallpaperControllerImpl::SetDriveFsDelegate(
std::unique_ptr<WallpaperDriveFsDelegate> drivefs_delegate) {
DCHECK(!drivefs_delegate_);
drivefs_delegate_ = std::move(drivefs_delegate);
}
bool WallpaperControllerImpl::CanSetUserWallpaper(
const AccountId& account_id) const {
if (IsInKioskMode()) {
return false;
}
if (IsWallpaperControlledByPolicy(account_id)) {
return false;
}
return true;
}
void WallpaperControllerImpl::SetCustomWallpaper(
const AccountId& account_id,
const base::FilePath& file_path,
WallpaperLayout layout,
bool preview_mode,
SetWallpaperCallback callback) {
DCHECK(Shell::Get()->session_controller()->IsActiveUserSessionStarted());
if (!CanSetUserWallpaper(account_id)) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kCustomized, SetWallpaperResult::kPermissionDenied);
std::move(callback).Run(false);
return;
}
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
ReadAndDecodeWallpaper(
base::BindOnce(&WallpaperControllerImpl::SetDecodedCustomWallpaper,
set_wallpaper_weak_factory_.GetWeakPtr(), account_id,
file_path.BaseName().value(), layout, preview_mode,
std::move(callback), file_path.value()),
file_path);
}
void WallpaperControllerImpl::SetDecodedCustomWallpaper(
const AccountId& account_id,
const std::string& file_name,
WallpaperLayout layout,
bool preview_mode,
SetWallpaperCallback callback,
const std::string& file_path,
const gfx::ImageSkia& image) {
DCHECK(Shell::Get()->session_controller()->IsActiveUserSessionStarted());
if (image.isNull() || !CanSetUserWallpaper(account_id)) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kCustomized, SetWallpaperResult::kDecodingError);
std::move(callback).Run(false);
return;
}
for (auto& observer : observers_) {
observer.OnUserSetWallpaper(account_id);
}
wallpaper_metrics_manager_->LogWallpaperResult(WallpaperType::kCustomized,
SetWallpaperResult::kSuccess);
std::move(callback).Run(true);
const bool is_active_user = IsActiveUser(account_id);
if (preview_mode) {
DCHECK(is_active_user);
confirm_preview_wallpaper_callback_ = base::BindOnce(
&WallpaperControllerImpl::SaveAndSetWallpaper, base::Unretained(this),
account_id, IsEphemeralUser(account_id), file_name, file_path,
WallpaperType::kCustomized, layout,
false, image);
reload_preview_wallpaper_callback_ = base::BindRepeating(
&WallpaperControllerImpl::ShowWallpaperImage, base::Unretained(this),
image,
WallpaperInfo{std::string(), layout,
WallpaperType::kCustomized, base::Time::Now(), file_path},
true, false);
reload_preview_wallpaper_callback_.Run();
} else {
SaveAndSetWallpaperWithCompletion(
account_id, IsEphemeralUser(account_id), file_name, file_path,
WallpaperType::kCustomized, layout,
is_active_user, image,
base::BindOnce(
&WallpaperControllerImpl::SaveWallpaperToDriveFsAndSyncInfo,
weak_factory_.GetWeakPtr(), account_id));
}
}
void WallpaperControllerImpl::SetOnlineWallpaper(
const OnlineWallpaperParams& params,
SetWallpaperCallback callback) {
DCHECK(callback);
DCHECK(Shell::Get()->session_controller()->IsActiveUserSessionStarted());
DVLOG(1) << __func__ << " params=" << params;
if (!CanSetUserWallpaper(params.account_id)) {
wallpaper_metrics_manager_->LogWallpaperResult(
params.daily_refresh_enabled ? WallpaperType::kDaily
: WallpaperType::kOnline,
SetWallpaperResult::kPermissionDenied);
std::move(callback).Run(false);
return;
}
std::unique_ptr<WallpaperInfo> new_info = CreateOnlineWallpaperInfo(
params, GetScheduleForOnlineWallpaper(params.collection_id), __func__);
if (!new_info) {
std::move(callback).Run(false);
return;
}
if (current_wallpaper_ &&
current_wallpaper_->wallpaper_info().MatchesAsset(*new_info)) {
DVLOG(1) << "Detected no change in online wallpaper";
std::move(callback).Run(true);
for (auto& observer : observers_) {
observer.OnWallpaperResized();
}
return;
}
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
for (auto& observer : observers_)
observer.OnOnlineWallpaperSet(params);
online_wallpaper_manager_.GetOnlineWallpaper(
wallpapers_dir_, params.account_id, *new_info,
base::BindOnce(&WallpaperControllerImpl::OnOnlineWallpaperDecoded,
set_wallpaper_weak_factory_.GetWeakPtr(),
params.account_id, params.preview_mode, *new_info,
std::move(callback)));
}
void WallpaperControllerImpl::SetGooglePhotosWallpaper(
const GooglePhotosWallpaperParams& params,
WallpaperController::SetWallpaperCallback callback) {
if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted() ||
!CanSetUserWallpaper(params.account_id)) {
wallpaper_metrics_manager_->LogWallpaperResult(
params.daily_refresh_enabled && !params.id.empty()
? WallpaperType::kDailyGooglePhotos
: WallpaperType::kOnceGooglePhotos,
SetWallpaperResult::kPermissionDenied);
std::move(callback).Run(false);
return;
}
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
if (params.daily_refresh_enabled) {
if (params.id.empty()) {
WallpaperInfo info;
if (!GetUserWallpaperInfo(params.account_id, &info) ||
info.type != WallpaperType::kDailyGooglePhotos) {
LOG(ERROR) << "Failed to get wallpaper info when disabling google "
"photos daily refresh.";
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOnceGooglePhotos,
SetWallpaperResult::kInvalidState);
std::move(callback).Run(false);
return;
}
std::move(callback).Run(true);
info.collection_id = std::string();
info.type = WallpaperType::kOnceGooglePhotos;
SetUserWallpaperInfo(params.account_id, info);
return;
} else {
wallpaper_controller_client_->FetchDailyGooglePhotosPhoto(
params.account_id, params.id,
base::BindOnce(
&WallpaperControllerImpl::OnDailyGooglePhotosPhotoFetched,
set_wallpaper_weak_factory_.GetWeakPtr(), params,
std::move(callback)));
}
} else {
wallpaper_controller_client_->FetchGooglePhotosPhoto(
params.account_id, params.id,
base::BindOnce(&WallpaperControllerImpl::OnGooglePhotosPhotoFetched,
set_wallpaper_weak_factory_.GetWeakPtr(), params,
std::move(callback)));
}
}
void WallpaperControllerImpl::SetGooglePhotosDailyRefreshAlbumId(
const AccountId& account_id,
const std::string& album_id) {
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info)) {
LOG(ERROR) << __func__ << " Failed to get user wallpaper info.";
return;
}
if (!album_id.empty()) {
info.type = WallpaperType::kDailyGooglePhotos;
info.collection_id = album_id;
}
if (album_id.empty() && info.type == WallpaperType::kDailyGooglePhotos) {
info.type = WallpaperType::kOnceGooglePhotos;
}
SetUserWallpaperInfo(account_id, info);
}
std::string WallpaperControllerImpl::GetGooglePhotosDailyRefreshAlbumId(
const AccountId& account_id) const {
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info))
return std::string();
if (info.type != WallpaperType::kDailyGooglePhotos)
return std::string();
return info.collection_id;
}
bool WallpaperControllerImpl::SetDailyGooglePhotosWallpaperIdCache(
const AccountId& account_id,
const DailyGooglePhotosIdCache& ids) {
return pref_manager_->SetDailyGooglePhotosWallpaperIdCache(account_id, ids);
}
bool WallpaperControllerImpl::GetDailyGooglePhotosWallpaperIdCache(
const AccountId& account_id,
DailyGooglePhotosIdCache& ids_out) const {
return pref_manager_->GetDailyGooglePhotosWallpaperIdCache(account_id,
ids_out);
}
void WallpaperControllerImpl::SetTimeOfDayWallpaper(
const AccountId& account_id,
SetTimeOfDayWallpaperCallback callback) {
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
GetCustomizationId(base::BindOnce(
&WallpaperControllerImpl::OnGetCustomizationIdForTimeOfDayWallpaper,
set_wallpaper_weak_factory_.GetWeakPtr(), account_id,
std::move(callback)));
}
bool WallpaperControllerImpl::IsTimeOfDayWallpaper() const {
return current_wallpaper_ &&
::ash::IsTimeOfDayWallpaper(
current_wallpaper_->wallpaper_info().collection_id);
}
void WallpaperControllerImpl::SetDefaultWallpaper(
const AccountId& account_id,
bool show_wallpaper,
SetWallpaperCallback callback) {
if (!CanSetUserWallpaper(account_id)) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDefault, SetWallpaperResult::kPermissionDenied);
std::move(callback).Run(false);
return;
}
RemoveUserWallpaper(account_id, base::DoNothing());
if (!SetDefaultWallpaperInfo(account_id, base::Time::Now())) {
LOG(ERROR) << "Initializing user wallpaper info fails. This should never "
"happen except in tests.";
}
if (show_wallpaper) {
wallpaper_cache_map_.erase(account_id);
SetDefaultWallpaperImpl(GetUserType(account_id), true,
std::move(callback));
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDefault, SetWallpaperResult::kSuccess);
std::move(callback).Run(true);
}
}
base::FilePath WallpaperControllerImpl::GetDefaultWallpaperPath(
user_manager::UserType user_type) {
const bool use_small =
(GetAppropriateResolution() == WallpaperResolution::kSmall);
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (user_type == user_manager::UserType::kGuest) {
const std::string_view switch_string = use_small
? switches::kGuestWallpaperSmall
: switches::kGuestWallpaperLarge;
return command_line->GetSwitchValuePath(switch_string);
} else if (user_type == user_manager::UserType::kChild) {
const std::string_view switch_string = use_small
? switches::kChildWallpaperSmall
: switches::kChildWallpaperLarge;
return command_line->GetSwitchValuePath(switch_string);
} else if (!customized_default_small_path_.empty()) {
DCHECK(!customized_default_large_path_.empty());
return use_small ? customized_default_small_path_
: customized_default_large_path_;
} else {
const std::string_view switch_string =
use_small ? switches::kDefaultWallpaperSmall
: switches::kDefaultWallpaperLarge;
return command_line->GetSwitchValuePath(switch_string);
}
}
void WallpaperControllerImpl::SetCustomizedDefaultWallpaperPaths(
const base::FilePath& customized_default_small_path,
const base::FilePath& customized_default_large_path) {
customized_default_small_path_ = customized_default_small_path;
customized_default_large_path_ = customized_default_large_path;
bool show_wallpaper = (GetWallpaperType() == WallpaperType::kDefault);
auto* active_user_session = GetActiveUserSession();
user_manager::UserType user_type = user_manager::UserType::kRegular;
if (active_user_session) {
LOG(WARNING) << "Set customized default wallpaper after login";
user_type = active_user_session->user_info.type;
}
SetDefaultWallpaperImpl(user_type, show_wallpaper, base::DoNothing());
}
void WallpaperControllerImpl::SetPolicyWallpaper(
const AccountId& account_id,
user_manager::UserType user_type,
const std::string& data) {
if (IsInKioskMode())
return;
DCHECK(user_type == user_manager::UserType::kRegular ||
user_type == user_manager::UserType::kPublicAccount);
const bool show_wallpaper = IsActiveUser(account_id);
if (bypass_decode_for_testing_) {
OnPolicyWallpaperDecoded(account_id, user_type, show_wallpaper,
CreateSolidColorWallpaper(kDefaultWallpaperColor));
return;
}
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
image_util::DecodeImageData(
base::BindOnce(&WallpaperControllerImpl::OnPolicyWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id, user_type,
show_wallpaper),
data_decoder::mojom::ImageCodec::kDefault, data);
}
void WallpaperControllerImpl::OnPolicyWallpaperDecoded(
const AccountId& account_id,
user_manager::UserType user_type,
bool show_wallpaper,
const gfx::ImageSkia& image) {
if (image.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kPolicy, SetWallpaperResult::kDecodingError);
return;
}
wallpaper_metrics_manager_->LogWallpaperResult(WallpaperType::kPolicy,
SetWallpaperResult::kSuccess);
const bool is_managed_guest =
(user_type == user_manager::UserType::kPublicAccount) ||
IsEphemeralUser(account_id);
SaveAndSetWallpaper(account_id, is_managed_guest, kPolicyWallpaperFile,
"", WallpaperType::kPolicy,
WALLPAPER_LAYOUT_CENTER_CROPPED, show_wallpaper, image);
}
void WallpaperControllerImpl::SetDevicePolicyWallpaperPath(
const base::FilePath& device_policy_wallpaper_path) {
const bool was_device_policy_wallpaper_enforced =
!device_policy_wallpaper_path_.empty();
device_policy_wallpaper_path_ = device_policy_wallpaper_path;
if (ShouldSetDevicePolicyWallpaper()) {
SetDevicePolicyWallpaper();
} else if (was_device_policy_wallpaper_enforced &&
device_policy_wallpaper_path.empty()) {
}
}
bool WallpaperControllerImpl::SetThirdPartyWallpaper(
const AccountId& account_id,
const std::string& file_name,
WallpaperLayout layout,
const gfx::ImageSkia& image) {
bool allowed_to_set_wallpaper = CanSetUserWallpaper(account_id);
bool allowed_to_show_wallpaper = IsActiveUser(account_id);
if (image.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kThirdParty, SetWallpaperResult::kFileNotFound);
return false;
}
if (allowed_to_set_wallpaper) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kThirdParty, SetWallpaperResult::kSuccess);
SaveAndSetWallpaperWithCompletion(
account_id, IsEphemeralUser(account_id), file_name,
"", WallpaperType::kCustomized, layout,
allowed_to_show_wallpaper, image,
base::BindOnce(
&WallpaperControllerImpl::SaveWallpaperToDriveFsAndSyncInfo,
weak_factory_.GetWeakPtr(), account_id));
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kThirdParty, SetWallpaperResult::kPermissionDenied);
}
return allowed_to_set_wallpaper && allowed_to_show_wallpaper;
}
void WallpaperControllerImpl::SetSeaPenWallpaper(
const AccountId& account_id,
const uint32_t image_id,
const bool preview_mode,
SetWallpaperCallback callback) {
DCHECK(Shell::Get()->session_controller()->IsActiveUserSessionStarted());
if (!CanSetUserWallpaper(account_id)) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kSeaPen, SetWallpaperResult::kPermissionDenied);
std::move(callback).Run(false);
return;
}
sea_pen_wallpaper_manager_.TouchFile(account_id, image_id);
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
sea_pen_wallpaper_manager_.GetImage(
account_id, image_id,
base::BindOnce(&WallpaperControllerImpl::OnSeaPenWallpaperDecoded,
set_wallpaper_weak_factory_.GetWeakPtr(), account_id,
image_id, preview_mode, std::move(callback)));
}
void WallpaperControllerImpl::ConfirmPreviewWallpaper() {
if (!confirm_preview_wallpaper_callback_) {
DCHECK(!reload_preview_wallpaper_callback_);
return;
}
std::move(confirm_preview_wallpaper_callback_).Run();
reload_preview_wallpaper_callback_.Reset();
if (ShouldApplyShield())
RepaintWallpaper();
for (auto& observer : observers_)
observer.OnWallpaperPreviewEnded();
}
void WallpaperControllerImpl::CancelPreviewWallpaper() {
if (!confirm_preview_wallpaper_callback_) {
return;
}
confirm_preview_wallpaper_callback_.Reset();
reload_preview_wallpaper_callback_.Reset();
ReloadWallpaper(false);
for (auto& observer : observers_)
observer.OnWallpaperPreviewEnded();
}
void WallpaperControllerImpl::UpdateCurrentWallpaperLayout(
const AccountId& account_id,
WallpaperLayout layout) {
if (!IsActiveUser(account_id))
return;
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info) ||
((info.type != WallpaperType::kCustomized) &&
(info.type != WallpaperType::kOnceGooglePhotos))) {
return;
}
if (info.layout == layout)
return;
info.layout = layout;
if (!SetUserWallpaperInfo(account_id, info)) {
LOG(ERROR) << "Setting user wallpaper info fails. This should never happen "
"except in tests.";
}
ShowUserWallpaper(account_id);
}
void WallpaperControllerImpl::ShowUserWallpaper(const AccountId& account_id) {
ShowUserWallpaper(account_id, GetUserType(account_id));
}
void WallpaperControllerImpl::ShowUserWallpaper(
const AccountId& account_id,
const user_manager::UserType user_type) {
current_account_id_ = account_id;
if (user_manager::User::TypeIsKiosk(user_type)) {
RepaintWallpaper();
return;
}
if (ShouldSetDevicePolicyWallpaper()) {
SetDevicePolicyWallpaper();
return;
}
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info)) {
if (!SetDefaultWallpaperInfo(account_id, base::Time::Min()))
return;
GetUserWallpaperInfo(account_id, &info);
}
gfx::ImageSkia user_wallpaper;
if (GetWallpaperFromCache(account_id, &user_wallpaper)) {
ShowWallpaperImage(user_wallpaper, info, false,
false);
return;
}
if (info.type == WallpaperType::kDefault) {
session_manager::SessionState session_state =
Shell::Get()->session_controller()->GetSessionState();
if (session_state == session_manager::SessionState::OOBE) {
ShowOobeWallpaper();
return;
}
wallpaper_cache_map_.erase(account_id);
SetDefaultWallpaperImpl(user_type, true,
base::DoNothing());
return;
}
if (IsOnlineWallpaper(info.type) ||
info.type == WallpaperType::kOnceGooglePhotos ||
info.type == WallpaperType::kDailyGooglePhotos ||
info.type == WallpaperType::kSeaPen) {
SetWallpaperFromInfo(account_id, info);
return;
}
CHECK(info.type == WallpaperType::kCustomized ||
info.type == WallpaperType::kPolicy)
<< " Got unhandled wallpaper type=" << base::to_underlying(info.type);
std::string sub_dir = GetCustomWallpaperSubdirForCurrentResolution();
base::FilePath wallpaper_path =
GetCustomWallpaperDir(sub_dir).Append(info.location);
base::FilePath cached_wallpaper_path;
if (GetPathFromCache(account_id, &cached_wallpaper_path) &&
cached_wallpaper_path == wallpaper_path) {
return;
}
wallpaper_cache_map_[account_id] =
CustomWallpaperElement(wallpaper_path, gfx::ImageSkia());
base::FilePath fallback_path =
GetCustomWallpaperDir(kOriginalWallpaperSubDir).Append(info.location);
sequenced_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&PathWithFallback, wallpaper_path, fallback_path),
base::BindOnce(&WallpaperControllerImpl::StartDecodeFromPath,
weak_factory_.GetWeakPtr(), account_id, user_type, info,
true));
}
void WallpaperControllerImpl::ShowSigninWallpaper() {
current_account_id_ = EmptyAccountId();
if (ShouldSetDevicePolicyWallpaper()) {
SetDevicePolicyWallpaper();
return;
}
if (IsOobeState()) {
ShowOobeWallpaper();
return;
}
SetDefaultWallpaperImpl(user_manager::UserType::kRegular,
true, base::DoNothing());
}
void WallpaperControllerImpl::ShowOneShotWallpaper(
const gfx::ImageSkia& image) {
const WallpaperInfo info = {std::string(),
WallpaperLayout::WALLPAPER_LAYOUT_STRETCH,
WallpaperType::kOneShot, base::Time::Now()};
ShowWallpaperImage(image, info, false,
false);
}
void WallpaperControllerImpl::ShowOverrideWallpaper(
const base::FilePath& image_path,
bool always_on_top) {
is_always_on_top_wallpaper_ = always_on_top;
is_override_wallpaper_ = true;
const WallpaperInfo info = {std::string(),
WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
WallpaperType::kOneShot, base::Time::Now()};
ReparentWallpaper();
ReadAndDecodeWallpaper(
base::BindOnce(&WallpaperControllerImpl::OnOverrideWallpaperDecoded,
weak_factory_.GetWeakPtr(), info),
image_path);
}
void WallpaperControllerImpl::RemoveOverrideWallpaper() {
if (!is_override_wallpaper_) {
DCHECK(!reload_override_wallpaper_callback_);
return;
}
is_always_on_top_wallpaper_ = false;
is_override_wallpaper_ = false;
reload_override_wallpaper_callback_.Reset();
ReparentWallpaper();
current_wallpaper_.reset();
ReloadWallpaper(false);
}
void WallpaperControllerImpl::RemoveUserWallpaper(
const AccountId& account_id,
base::OnceClosure on_removed) {
wallpaper_cache_map_.erase(account_id);
pref_manager_->RemoveUserWallpaperInfo(account_id);
RemoveUserWallpaperImpl(account_id, std::move(on_removed));
}
void WallpaperControllerImpl::RemovePolicyWallpaper(
const AccountId& account_id) {
if (!IsWallpaperControlledByPolicy(account_id))
return;
const bool show_wallpaper =
Shell::Get()->session_controller()->IsActiveUserSessionStarted();
pref_manager_->RemoveUserWallpaperInfo(account_id);
SetDefaultWallpaper(account_id, show_wallpaper, base::DoNothing());
}
void WallpaperControllerImpl::SetAnimationDuration(
base::TimeDelta animation_duration) {
animation_duration_ = animation_duration;
}
void WallpaperControllerImpl::OpenWallpaperPickerIfAllowed() {
const auto* session = GetActiveUserSession();
if (wallpaper_controller_client_ && session &&
CanSetUserWallpaper(session->user_info.account_id)) {
wallpaper_controller_client_->OpenWallpaperPicker();
}
}
void WallpaperControllerImpl::MinimizeInactiveWindows(
const std::string& user_id_hash) {
if (!window_state_manager_)
window_state_manager_ = std::make_unique<WallpaperWindowStateManager>();
window_state_manager_->MinimizeInactiveWindows(user_id_hash);
}
void WallpaperControllerImpl::RestoreMinimizedWindows(
const std::string& user_id_hash) {
if (!window_state_manager_) {
DVLOG(1) << "No minimized window state saved";
return;
}
window_state_manager_->RestoreMinimizedWindows(user_id_hash);
}
void WallpaperControllerImpl::AddObserver(
WallpaperControllerObserver* observer) {
observers_.AddObserver(observer);
}
void WallpaperControllerImpl::RemoveObserver(
WallpaperControllerObserver* observer) {
observers_.RemoveObserver(observer);
}
gfx::ImageSkia WallpaperControllerImpl::GetWallpaperImage() {
return GetWallpaper();
}
void WallpaperControllerImpl::LoadPreviewImage(
LoadPreviewImageCallback callback) {
if (!current_wallpaper_) {
std::move(callback).Run(nullptr);
return;
}
auto image = current_wallpaper_->image();
image.MakeThreadSafe();
if (!IsOnlineWallpaper(current_wallpaper_->wallpaper_info().type)) {
sequenced_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(&EncodeAndResizeImage, image),
std::move(callback));
return;
}
auto variants = current_wallpaper_->wallpaper_info().variants;
auto it =
std::ranges::find(variants, backdrop::Image::IMAGE_TYPE_PREVIEW_MODE,
&OnlineWallpaperVariant::type);
if (it == variants.end()) {
sequenced_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(&EncodeAndResizeImage, image),
std::move(callback));
return;
}
const auto& preview_variant = *it;
wallpaper_file_manager_->LoadOnlineWallpaperPreview(
wallpapers_dir_, preview_variant.raw_url, std::move(callback));
}
bool WallpaperControllerImpl::IsWallpaperBlurredForLockState() const {
return blur_manager_->is_wallpaper_blurred_for_lock_state();
}
bool WallpaperControllerImpl::IsActiveUserWallpaperControlledByPolicy() {
const UserSession* const active_user_session = GetActiveUserSession();
if (!active_user_session)
return false;
return IsWallpaperControlledByPolicy(
active_user_session->user_info.account_id);
}
bool WallpaperControllerImpl::IsWallpaperControlledByPolicy(
const AccountId& account_id) const {
WallpaperInfo info;
return GetUserWallpaperInfo(account_id, &info) &&
info.type == WallpaperType::kPolicy;
}
std::optional<WallpaperInfo>
WallpaperControllerImpl::GetActiveUserWallpaperInfo() const {
WallpaperInfo info;
const UserSession* const active_user_session = GetActiveUserSession();
if (!active_user_session) {
return std::nullopt;
}
return GetWallpaperInfoForAccountId(
active_user_session->user_info.account_id);
}
std::optional<WallpaperInfo>
WallpaperControllerImpl::GetWallpaperInfoForAccountId(
const AccountId& account_id) const {
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info)) {
return std::nullopt;
}
return info;
}
void WallpaperControllerImpl::OnDeviceWallpaperImageFilePathUpdated(
const base::FilePath& path) {
SetDevicePolicyWallpaperPath(path);
}
void WallpaperControllerImpl::OnDidApplyDisplayChanges() {
gfx::Size max_display_size = GetMaxDisplaySizeInNative();
if (current_max_display_size_ == max_display_size)
return;
current_max_display_size_ = max_display_size;
if (wallpaper_mode_ == WALLPAPER_IMAGE && current_wallpaper_) {
timer_.Stop();
GetInternalDisplayCompositorLock();
timer_.Start(
FROM_HERE, wallpaper_reload_delay_,
base::BindOnce(&WallpaperControllerImpl::ReloadWallpaper,
weak_factory_.GetWeakPtr(), false));
}
}
void WallpaperControllerImpl::OnRootWindowAdded(aura::Window* root_window) {
if (wallpaper_mode_ == WALLPAPER_NONE)
return;
gfx::Size max_display_size = GetMaxDisplaySizeInNative();
if (current_max_display_size_ != max_display_size) {
current_max_display_size_ = max_display_size;
if (wallpaper_mode_ == WALLPAPER_IMAGE && current_wallpaper_)
ReloadWallpaper(true);
}
UpdateWallpaperForRootWindow(root_window, false,
true);
}
void WallpaperControllerImpl::OnShellInitialized() {
auto* shell = Shell::Get();
shell->overview_controller()->AddObserver(this);
shell->dark_light_mode_controller()->AddCheckpointObserver(this);
daily_refresh_scheduler_ = std::make_unique<WallpaperDailyRefreshScheduler>();
time_of_day_scheduler_ = std::make_unique<WallpaperTimeOfDayScheduler>();
if (!time_of_day_scheduler_observation_.IsObserving()) {
time_of_day_scheduler_observation_.Observe(time_of_day_scheduler_.get());
}
if (!daily_refresh_observation_.IsObserving()) {
daily_refresh_observation_.Observe(daily_refresh_scheduler_.get());
}
}
void WallpaperControllerImpl::OnShellDestroying() {
auto* shell = Shell::Get();
shell->overview_controller()->RemoveObserver(this);
shell->dark_light_mode_controller()->RemoveCheckpointObserver(this);
daily_refresh_observation_.Reset();
time_of_day_scheduler_observation_.Reset();
}
void WallpaperControllerImpl::OnWallpaperResized() {
CalculateWallpaperColors();
compositor_lock_.reset();
for (auto& observer : observers_) {
observer.OnWallpaperResized();
}
}
void WallpaperControllerImpl::OnColorCalculationComplete(
const WallpaperInfo& info,
const WallpaperCalculatedColors& wallpaper_calculated_colors) {
DCHECK(current_wallpaper_->wallpaper_info().MatchesAsset(info));
pref_manager_->CacheKMeanColor(info.location,
wallpaper_calculated_colors.k_mean_color);
pref_manager_->CacheCelebiColor(info.location,
wallpaper_calculated_colors.celebi_color);
SetCalculatedColors(wallpaper_calculated_colors);
color_calculator_.reset();
}
void WallpaperControllerImpl::OnActiveUserSessionChanged(
const AccountId& account_id) {
MaybeClosePreviewWallpaper();
WallpaperInfo info;
pref_manager_->GetLocalWallpaperInfo(account_id, &info);
if (info.type == WallpaperType::kOnceGooglePhotos)
CheckGooglePhotosStaleness(account_id, info);
}
void WallpaperControllerImpl::OnOobeDialogStateChanged(OobeDialogState state) {
oobe_state_ = state;
}
void WallpaperControllerImpl::OnSessionStateChanged(
session_manager::SessionState state) {
if (IsDevicePolicyWallpaper() && !ShouldSetDevicePolicyWallpaper())
ReloadWallpaper(false);
if (IsOobeWallpaper()) {
ReloadWallpaper(false);
}
CalculateWallpaperColors();
is_session_active_ = state == session_manager::SessionState::ACTIVE;
if (wallpaper_mode_ == WALLPAPER_IMAGE &&
(state == session_manager::SessionState::ACTIVE ||
state == session_manager::SessionState::LOCKED ||
state == session_manager::SessionState::LOGIN_SECONDARY)) {
UpdateWallpaperForAllRootWindows(true);
} else {
ReparentWallpaper();
}
}
void WallpaperControllerImpl::OnDisplayTabletStateChanged(
display::TabletState state) {
if (display::IsTabletStateChanging(state)) {
return;
}
RepaintWallpaper();
}
void WallpaperControllerImpl::OnCheckpointChanged(
const ScheduledFeature* src,
const ScheduleCheckpoint new_checkpoint) {
if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted()) {
return;
}
AccountId account_id = GetActiveAccountId();
WallpaperInfo info;
if (!pref_manager_->GetUserWallpaperInfo(account_id, &info)) {
return;
}
if (src == daily_refresh_scheduler_.get()) {
DVLOG(1) << __func__ << " notified by daily_refresh_scheduler_";
for (auto& observer : observers_) {
observer.OnDailyRefreshCheckpointChanged();
}
if (daily_refresh_scheduler_->ShouldRefreshWallpaper(info)) {
UpdateDailyRefreshWallpaper();
}
if (info.type == WallpaperType::kOnceGooglePhotos) {
CheckGooglePhotosStaleness(account_id, info);
}
return;
}
if (!IsOnlineWallpaper(info.type) ||
src != &GetScheduleForOnlineWallpaper(info.collection_id)) {
return;
}
variant_info_fetcher_.FetchOnlineWallpaper(
account_id, info,
base::BindOnce(&WallpaperControllerImpl::RepaintOnlineWallpaper,
set_wallpaper_weak_factory_.GetWeakPtr()));
}
void WallpaperControllerImpl::OnNativeThemeUpdated(
ui::NativeTheme* observed_theme) {
RepaintWallpaper();
}
void WallpaperControllerImpl::OnOverviewModeWillStart() {
MaybeClosePreviewWallpaper();
}
void WallpaperControllerImpl::OnOverviewModeStarting() {
if (display::Screen::Get()->InTabletMode()) {
RepaintWallpaper();
}
}
void WallpaperControllerImpl::OnOverviewModeEnded() {
if (display::Screen::Get()->InTabletMode()) {
RepaintWallpaper();
}
}
void WallpaperControllerImpl::CompositorLockTimedOut() {
compositor_lock_.reset();
}
void WallpaperControllerImpl::OnActiveUserPrefServiceChanged(
PrefService* pref_service) {
AccountId account_id = GetActiveAccountId();
WallpaperInfo local_info;
const bool has_local_info =
pref_manager_->GetLocalWallpaperInfo(account_id, &local_info);
const bool is_oobe_or_demo =
IsOobeState() || (demo_mode::IsDeviceInDemoMode() &&
features::IsDemoModeWallpaperUpdateEnabled());
bool should_set_time_of_day_wallpaper =
is_oobe_or_demo && has_local_info &&
local_info.type == WallpaperType::kDefault &&
features::IsTimeOfDayWallpaperEnabled();
if (should_set_time_of_day_wallpaper) {
DVLOG(0) << __func__ << " Setting default time of day wallpaper.";
SetTimeOfDayWallpaper(
account_id,
base::BindOnce(
&WallpaperControllerImpl::OnTimeOfDayWallpaperSetAfterOobe,
weak_factory_.GetWeakPtr()));
}
if (wallpaper_controller_client_->IsWallpaperSyncEnabled(account_id)) {
WallpaperInfo synced_info;
bool has_synced_info =
pref_manager_->GetSyncedWallpaperInfo(account_id, &synced_info);
DVLOG(1) << __func__ << " has_synced_info=" << has_synced_info;
if (!has_synced_info && has_local_info &&
WallpaperPrefManager::ShouldSyncOut(local_info)) {
if (local_info.type == WallpaperType::kCustomized) {
base::FilePath source = GetCustomWallpaperDir(kOriginalWallpaperSubDir)
.Append(local_info.location);
SaveWallpaperToDriveFsAndSyncInfo(account_id, source);
} else {
pref_manager_->SetSyncedWallpaperInfo(account_id, local_info);
}
}
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(
Shell::Get()->session_controller()->GetActivePrefService());
pref_change_registrar_->Add(
prefs::kSyncableWallpaperInfo,
base::BindRepeating(&WallpaperControllerImpl::SyncLocalAndRemotePrefs,
weak_factory_.GetWeakPtr(), account_id));
SyncLocalAndRemotePrefs(account_id);
}
OnCheckpointChanged(daily_refresh_scheduler_.get(),
daily_refresh_scheduler_->current_checkpoint());
}
void WallpaperControllerImpl::ShowDefaultWallpaperForTesting() {
SetDefaultWallpaperImpl(user_manager::UserType::kRegular,
true, base::DoNothing());
}
void WallpaperControllerImpl::CreateEmptyWallpaperForTesting() {
ResetCalculatedColors();
current_wallpaper_.reset();
wallpaper_mode_ = WALLPAPER_IMAGE;
UpdateWallpaperForAllRootWindows(false);
SetCalculatedColors(WallpaperCalculatedColors(
SK_ColorWHITE,
gfx::kGoogleBlue400));
}
void WallpaperControllerImpl::ReloadWallpaperForTesting(bool clear_cache) {
ReloadWallpaper(clear_cache);
}
void WallpaperControllerImpl::OverrideDriveFsDelegateForTesting(
std::unique_ptr<WallpaperDriveFsDelegate> drivefs_delegate) {
CHECK_IS_TEST();
drivefs_delegate_ = std::move(drivefs_delegate);
}
void WallpaperControllerImpl::UpdateWallpaperForRootWindow(
aura::Window* root_window,
bool lock_state_changed,
bool new_root) {
DCHECK_EQ(WALLPAPER_IMAGE, wallpaper_mode_);
auto* wallpaper_widget_controller =
RootWindowController::ForWindow(root_window)
->wallpaper_widget_controller();
if (lock_state_changed || new_root) {
wallpaper_widget_controller->Reparent(GetWallpaperContainerId());
}
wallpaper_widget_controller->wallpaper_view()->ClearCachedImage();
const bool changed = blur_manager_->UpdateBlurForRootWindow(
root_window, lock_state_changed, new_root, GetWallpaperType());
if (changed) {
for (auto& observer : observers_) {
observer.OnWallpaperBlurChanged();
}
}
}
void WallpaperControllerImpl::UpdateWallpaperForAllRootWindows(
bool lock_state_changed) {
for (aura::Window* root : Shell::GetAllRootWindows())
UpdateWallpaperForRootWindow(root, lock_state_changed, false);
current_max_display_size_ = GetMaxDisplaySizeInNative();
}
bool WallpaperControllerImpl::ReparentWallpaper() {
auto container = GetWallpaperContainerId();
bool moved = false;
for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
moved |= root_window_controller->wallpaper_widget_controller()->Reparent(
container);
}
return moved;
}
int WallpaperControllerImpl::GetWallpaperContainerId() {
if (is_always_on_top_wallpaper_) {
return kShellWindowId_AlwaysOnTopWallpaperContainer;
}
return is_session_active_ ? kShellWindowId_WallpaperContainer
: kShellWindowId_LockScreenWallpaperContainer;
}
void WallpaperControllerImpl::RemoveUserWallpaperImpl(
const AccountId& account_id,
base::OnceClosure on_removed) {
if (wallpaper_controller_client_) {
wallpaper_controller_client_->GetFilesId(
account_id,
base::BindOnce(
&WallpaperControllerImpl::RemoveUserWallpaperImplWithFilesId,
weak_factory_.GetWeakPtr(), account_id, std::move(on_removed)));
} else {
LOG(ERROR) << "Failed to remove wallpaper. wallpaper_controller_client_ no "
"longer exists.";
}
}
void WallpaperControllerImpl::RemoveUserWallpaperImplWithFilesId(
const AccountId& account_id,
base::OnceClosure on_removed,
const std::string& wallpaper_files_id) {
if (wallpaper_files_id.empty())
return;
std::vector<base::FilePath> files_to_remove;
base::FilePath wallpaper_path = GetCustomWallpaperDir(kSmallWallpaperSubDir);
files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
base::ThreadPool::PostTaskAndReply(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&DeleteWallpaperInList, std::move(files_to_remove)),
std::move(on_removed));
}
void WallpaperControllerImpl::SetDefaultWallpaperImpl(
user_manager::UserType user_type,
bool show_wallpaper,
SetWallpaperCallback callback) {
if (IsInKioskMode()) {
std::move(callback).Run(false);
return;
}
const bool use_small =
(GetAppropriateResolution() == WallpaperResolution::kSmall);
WallpaperLayout layout =
use_small ? WALLPAPER_LAYOUT_CENTER : WALLPAPER_LAYOUT_CENTER_CROPPED;
base::FilePath file_path = GetDefaultWallpaperPath(user_type);
if (!cached_default_wallpaper_.image.isNull() &&
cached_default_wallpaper_.file_path == file_path) {
OnDefaultWallpaperDecoded(file_path, layout, show_wallpaper,
std::move(callback),
cached_default_wallpaper_.image);
} else {
ReadAndDecodeWallpaper(
base::BindOnce(&WallpaperControllerImpl::OnDefaultWallpaperDecoded,
weak_factory_.GetWeakPtr(), file_path, layout,
show_wallpaper, std::move(callback)),
file_path);
}
}
bool WallpaperControllerImpl::WallpaperIsAlreadyLoaded(
const gfx::ImageSkia& image,
bool compare_layouts,
WallpaperLayout layout) const {
if (!current_wallpaper_)
return false;
if (compare_layouts && layout != current_wallpaper_->wallpaper_info().layout)
return false;
return WallpaperResizer::GetImageId(image) ==
current_wallpaper_->original_image_id();
}
void WallpaperControllerImpl::ReadAndDecodeWallpaper(
image_util::DecodeImageCallback callback,
const base::FilePath& file_path) {
decode_requests_for_testing_.push_back(file_path);
if (bypass_decode_for_testing_) {
std::move(callback).Run(CreateSolidColorWallpaper(kDefaultWallpaperColor));
return;
}
image_util::DecodeImageFile(std::move(callback), file_path);
}
bool WallpaperControllerImpl::SetDefaultWallpaperInfo(
const AccountId& account_id,
const base::Time& date) {
const WallpaperInfo info = {std::string(),
WALLPAPER_LAYOUT_CENTER_CROPPED,
WallpaperType::kDefault, date};
return SetUserWallpaperInfo(account_id, info);
}
void WallpaperControllerImpl::OnWallpaperVariantsFetched(
WallpaperType type,
SetWallpaperCallback callback,
std::optional<OnlineWallpaperParams> params) {
DCHECK(IsOnlineWallpaper(type));
if (params) {
SetOnlineWallpaper(*params, std::move(callback));
return;
}
std::move(callback).Run(false);
wallpaper_metrics_manager_->LogWallpaperResult(
type, SetWallpaperResult::kRequestFailure);
}
void WallpaperControllerImpl::RepaintOnlineWallpaper(
std::optional<OnlineWallpaperParams> params) {
if (!params) {
LOG(ERROR) << "Fetching online variant failed";
return;
}
std::unique_ptr<WallpaperInfo> new_info = CreateOnlineWallpaperInfo(
*params, GetScheduleForOnlineWallpaper(params->collection_id), __func__);
if (!new_info) {
return;
}
if (current_wallpaper_ &&
current_wallpaper_->wallpaper_info().MatchesAsset(*new_info)) {
DVLOG(1) << "Detected no change in online wallpaper asset";
return;
}
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
online_wallpaper_manager_.GetOnlineWallpaper(
wallpapers_dir_, params->account_id, *new_info,
base::BindOnce(&WallpaperControllerImpl::OnOnlineWallpaperDecoded,
set_wallpaper_weak_factory_.GetWeakPtr(),
params->account_id, params->preview_mode, *new_info,
base::DoNothing()));
}
void WallpaperControllerImpl::OnOnlineWallpaperDecoded(
const AccountId& account_id,
bool preview_mode,
WallpaperInfo wallpaper_info,
SetWallpaperCallback callback,
const gfx::ImageSkia& image) {
DCHECK(callback);
if (image.isNull()) {
std::move(callback).Run(false);
wallpaper_metrics_manager_->LogWallpaperResult(
wallpaper_info.type, SetWallpaperResult::kDecodingError);
LOG(ERROR) << "Failed to decode online wallpaper.";
return;
} else {
for (auto& observer : observers_) {
observer.OnUserSetWallpaper(account_id);
}
wallpaper_metrics_manager_->LogWallpaperResult(
wallpaper_info.type, SetWallpaperResult::kSuccess);
}
const bool is_active_user = IsActiveUser(account_id);
if (current_wallpaper_ &&
current_wallpaper_->wallpaper_info().MatchesSelection(wallpaper_info)) {
DVLOG(1) << "Detected a change in asset for the same wallpaper.";
wallpaper_info.date = current_wallpaper_->wallpaper_info().date;
}
if (preview_mode) {
DCHECK(is_active_user);
std::move(callback).Run(true);
confirm_preview_wallpaper_callback_ = base::BindOnce(
&WallpaperControllerImpl::SetWallpaperImpl, base::Unretained(this),
account_id, wallpaper_info, image, false);
reload_preview_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
base::Unretained(this), image, wallpaper_info,
true, false);
reload_preview_wallpaper_callback_.Run();
} else {
std::move(callback).Run(true);
SetWallpaperImpl(account_id, wallpaper_info, image,
is_active_user);
}
}
void WallpaperControllerImpl::ShowOobeWallpaper() {
GetCustomizationId(
base::BindOnce(&WallpaperControllerImpl::OnGetCustomizationIdForOobe,
set_wallpaper_weak_factory_.GetWeakPtr()));
}
void WallpaperControllerImpl::OnGetCustomizationIdForOobe(
std::optional<std::string_view> customization_id) {
base::FilePath file_path;
if (features::IsBootAnimationEnabled()) {
const base::FilePath directory_path(
FILE_PATH_LITERAL("/usr/share/chromeos-assets/animated_splash_screen"));
const base::FilePath file_name(
customization_id ==
wallpaper_constants::kAlternateWallpaperCustomizationId
? FILE_PATH_LITERAL("oobe_wallpaper_navi.jpg")
: FILE_PATH_LITERAL("oobe_wallpaper.jpg"));
DVLOG(1) << __func__ << " loading file_name " << file_name;
file_path = directory_path.Append(file_name);
} else {
file_path = GetDefaultWallpaperPath(user_manager::UserType::kRegular);
}
if (!cached_oobe_wallpaper_.image.isNull() &&
cached_oobe_wallpaper_.file_path == file_path) {
OnOobeWallpaperDecoded(file_path, cached_oobe_wallpaper_.image);
} else {
ReadAndDecodeWallpaper(
base::BindOnce(&WallpaperControllerImpl::OnOobeWallpaperDecoded,
weak_factory_.GetWeakPtr(), file_path),
file_path);
}
}
void WallpaperControllerImpl::OnOobeWallpaperDecoded(
const base::FilePath& path,
const gfx::ImageSkia& image) {
if (path.empty() || image.isNull()) {
LOG(ERROR) << "Failed to decode OOBE wallpaper.";
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOobe, SetWallpaperResult::kDecodingError);
cached_oobe_wallpaper_.image =
CreateSolidColorWallpaper(kOobeWallpaperColor);
cached_oobe_wallpaper_.file_path.clear();
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOobe, SetWallpaperResult::kSuccess);
cached_oobe_wallpaper_.image = image;
cached_oobe_wallpaper_.file_path = path;
}
const bool use_small =
(GetAppropriateResolution() == WallpaperResolution::kSmall);
WallpaperLayout layout =
use_small ? WallpaperLayout::WALLPAPER_LAYOUT_CENTER
: WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED;
WallpaperInfo info(cached_oobe_wallpaper_.file_path.value(), layout,
WallpaperType::kOobe, base::Time::Now());
ShowWallpaperImage(cached_oobe_wallpaper_.image, info,
false, false);
}
bool WallpaperControllerImpl::IsOobeWallpaper() const {
return current_wallpaper_ &&
current_wallpaper_->wallpaper_info().type == WallpaperType::kOobe;
}
void WallpaperControllerImpl::OnGooglePhotosPhotoFetched(
GooglePhotosWallpaperParams params,
SetWallpaperCallback callback,
ash::personalization_app::mojom::GooglePhotosPhotoPtr photo,
bool success) {
DCHECK(success || !photo);
if (!success) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOnceGooglePhotos, SetWallpaperResult::kRequestFailure);
std::move(callback).Run(false);
return;
}
if (photo.is_null()) {
WallpaperInfo wallpaper_info;
if (GetUserWallpaperInfo(params.account_id, &wallpaper_info) &&
wallpaper_info.location == params.id) {
if (params.account_id.HasAccountIdKey()) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(base::IgnoreResult(&base::DeletePathRecursively),
GetUserGooglePhotosWallpaperDir(params.account_id)));
}
wallpaper_cache_map_.erase(params.account_id);
SetDefaultWallpaper(params.account_id,
IsActiveUser(params.account_id),
base::DoNothing());
return;
}
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOnceGooglePhotos, SetWallpaperResult::kFileNotFound);
std::move(callback).Run(false);
return;
}
params.dedup_key = photo->dedup_key;
google_photos_wallpaper_manager_.GetGooglePhotosWallpaper(
GetUserGooglePhotosWallpaperDir(params.account_id), params,
std::move(photo),
base::BindOnce(&WallpaperControllerImpl::OnGooglePhotosWallpaperDecoded,
set_wallpaper_weak_factory_.GetWeakPtr(), params,
std::move(callback)));
}
void WallpaperControllerImpl::OnDailyGooglePhotosPhotoFetched(
const GooglePhotosWallpaperParams& params,
RefreshWallpaperCallback callback,
ash::personalization_app::mojom::GooglePhotosPhotoPtr photo,
bool success) {
DCHECK(success || !photo);
if (!success || photo.is_null()) {
std::move(callback).Run(false);
WallpaperInfo info;
if (GetUserWallpaperInfo(params.account_id, &info) &&
info.collection_id == params.id) {
if (success) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDailyGooglePhotos,
SetWallpaperResult::kFileNotFound);
SetDefaultWallpaper(params.account_id,
IsActiveUser(params.account_id),
base::DoNothing());
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDailyGooglePhotos,
SetWallpaperResult::kRequestFailure);
}
}
return;
}
auto on_load = base::BindOnce(
&WallpaperControllerImpl::OnDailyGooglePhotosWallpaperDecoded,
set_wallpaper_weak_factory_.GetWeakPtr(), params.account_id, photo->id,
params.id, photo->dedup_key, std::move(callback));
google_photos_wallpaper_manager_.GetGooglePhotosWallpaper(
GetUserGooglePhotosWallpaperDir(params.account_id), params,
std::move(photo), std::move(on_load));
}
void WallpaperControllerImpl::OnDailyGooglePhotosWallpaperDecoded(
const AccountId& account_id,
const std::string& photo_id,
const std::string& album_id,
std::optional<std::string> dedup_key,
RefreshWallpaperCallback callback,
const gfx::ImageSkia& image) {
DCHECK(callback);
if (image.isNull()) {
std::move(callback).Run(false);
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDailyGooglePhotos, SetWallpaperResult::kDecodingError);
return;
}
std::move(callback).Run(true);
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDailyGooglePhotos, SetWallpaperResult::kSuccess);
WallpaperInfo wallpaper_info(
{account_id, album_id, true,
ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
false, std::nullopt});
wallpaper_info.location = photo_id;
wallpaper_info.dedup_key = dedup_key;
SetWallpaperImpl(account_id, wallpaper_info, image, true);
}
void WallpaperControllerImpl::OnGooglePhotosWallpaperDecoded(
const GooglePhotosWallpaperParams& params,
SetWallpaperCallback callback,
const gfx::ImageSkia& image) {
DCHECK(callback);
if (image.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOnceGooglePhotos, SetWallpaperResult::kDecodingError);
std::move(callback).Run(false);
return;
}
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOnceGooglePhotos, SetWallpaperResult::kSuccess);
for (auto& observer : observers_) {
observer.OnUserSetWallpaper(params.account_id);
}
std::move(callback).Run(true);
bool is_active_user = IsActiveUser(params.account_id);
WallpaperInfo wallpaper_info(params);
if (params.preview_mode) {
DCHECK(is_active_user);
confirm_preview_wallpaper_callback_ = base::BindOnce(
&WallpaperControllerImpl::SetWallpaperImpl, base::Unretained(this),
params.account_id, wallpaper_info, image,
false);
reload_preview_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
base::Unretained(this), image, wallpaper_info,
true, false);
reload_preview_wallpaper_callback_.Run();
} else {
SetWallpaperImpl(params.account_id, wallpaper_info, image,
is_active_user);
}
}
void WallpaperControllerImpl::SetWallpaperImpl(
const AccountId& account_id,
const WallpaperInfo& wallpaper_info,
const gfx::ImageSkia& image,
bool show_wallpaper) {
DCHECK(!image.isNull()) << " image should not be empty";
if (!SetUserWallpaperInfo(account_id, wallpaper_info)) {
LOG(ERROR) << "Setting user wallpaper info fails. This should never happen "
"except in tests.";
}
if (show_wallpaper) {
ShowWallpaperImage(image, wallpaper_info, false,
false);
}
wallpaper_cache_map_[account_id] =
CustomWallpaperElement(base::FilePath(), image);
}
void WallpaperControllerImpl::SetWallpaperFromInfo(const AccountId& account_id,
const WallpaperInfo& info) {
if (info.type == WallpaperType::kDefault) {
LOG(WARNING) << "Setting a default wallpaper from info for user: "
<< account_id.Serialize()
<< " .This should only happen in test.";
SetDefaultWallpaperImpl(GetUserType(account_id), true,
base::DoNothing());
return;
}
DCHECK(!info.location.empty()) << " location should not be empty";
if (IsOnlineWallpaper(info.type)) {
auto wallpaper_path = GetOnlineWallpaperFilePath(
wallpapers_dir_, GURL(info.location), GetAppropriateResolution());
if (current_wallpaper_ &&
current_wallpaper_->wallpaper_info().MatchesAsset(info)) {
return;
}
wallpaper_file_manager_->LoadWallpaper(
info.type, wallpapers_dir_, info.location,
base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id, wallpaper_path,
info, true));
return;
}
if (info.type == WallpaperType::kOnceGooglePhotos ||
info.type == WallpaperType::kDailyGooglePhotos) {
auto path =
GetUserGooglePhotosWallpaperDir(account_id).Append(info.location);
wallpaper_file_manager_->LoadWallpaper(
info.type, GetUserGooglePhotosWallpaperDir(account_id), info.location,
base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id, path, info,
true));
return;
}
if (info.type == WallpaperType::kSeaPen) {
const auto user_sea_pen_wallpaper_dir =
GetUserSeaPenWallpaperDir(account_id);
wallpaper_file_manager_->LoadWallpaper(
WallpaperType::kSeaPen, user_sea_pen_wallpaper_dir, info.location,
base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id,
user_sea_pen_wallpaper_dir.Append(info.location)
.ReplaceExtension(".jpg"),
info, true));
return;
}
LOG(ERROR) << "Wallpaper reverts to default unexpected.";
wallpaper_cache_map_.erase(account_id);
SetDefaultWallpaperImpl(GetUserType(account_id), true,
base::DoNothing());
}
void WallpaperControllerImpl::OnDefaultWallpaperDecoded(
const base::FilePath& path,
WallpaperLayout layout,
bool show_wallpaper,
SetWallpaperCallback callback,
const gfx::ImageSkia& image) {
if (image.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDefault, SetWallpaperResult::kDecodingError);
cached_default_wallpaper_.image =
CreateSolidColorWallpaper(kDefaultWallpaperColor);
cached_default_wallpaper_.file_path.clear();
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDefault, SetWallpaperResult::kSuccess);
cached_default_wallpaper_.image = image;
cached_default_wallpaper_.file_path = path;
}
std::move(callback).Run(true);
if (show_wallpaper) {
WallpaperInfo info(cached_default_wallpaper_.file_path.value(), layout,
WallpaperType::kDefault, base::Time::Now());
ShowWallpaperImage(cached_default_wallpaper_.image, info,
false, false);
}
}
void WallpaperControllerImpl::OnSeaPenWallpaperDecoded(
const AccountId& account_id,
const uint32_t sea_pen_image_id,
const bool preview_mode,
SetWallpaperCallback callback,
const gfx::ImageSkia& image_skia) {
if (image_skia.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kSeaPen, SetWallpaperResult::kDecodingError);
std::move(callback).Run(false);
return;
}
if (IsEphemeralUser(account_id)) {
DCHECK(features::IsSeaPenDemoModeEnabled());
const auto cache_file_path =
base::FilePath("in_memory_cache")
.Append(wallpaper_constants::kSeaPenWallpaperDirName)
.Append(base::NumberToString(sea_pen_image_id))
.AddExtension(".jpg");
OnSeaPenWallpaperSavedToPublic(account_id, image_skia, sea_pen_image_id,
false, std::move(callback),
cache_file_path);
return;
}
wallpaper_file_manager_->SaveWallpaperToDisk(
WallpaperType::kSeaPen, GetUserSeaPenWallpaperDir(account_id),
base::FilePath(base::NumberToString(sea_pen_image_id))
.AddExtension(".jpg")
.value(),
WALLPAPER_LAYOUT_CENTER_CROPPED, image_skia,
base::BindOnce(&WallpaperControllerImpl::OnSeaPenWallpaperSavedToPublic,
set_wallpaper_weak_factory_.GetWeakPtr(), account_id,
image_skia, sea_pen_image_id, preview_mode,
std::move(callback)));
}
void WallpaperControllerImpl::OnSeaPenWallpaperSavedToPublic(
const AccountId& account_id,
const gfx::ImageSkia& image_skia,
const uint32_t sea_pen_image_id,
const bool preview_mode,
SetWallpaperCallback callback,
const base::FilePath& file_path) {
if (file_path.empty()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kSeaPen, SetWallpaperResult::kFileNotFound);
std::move(callback).Run(false);
return;
}
wallpaper_metrics_manager_->LogWallpaperResult(WallpaperType::kSeaPen,
SetWallpaperResult::kSuccess);
for (auto& observer : observers_) {
observer.OnUserSetWallpaper(account_id);
}
std::move(callback).Run(true);
WallpaperInfo wallpaper_info(base::NumberToString(sea_pen_image_id),
WALLPAPER_LAYOUT_CENTER_CROPPED,
WallpaperType::kSeaPen, base::Time::Now());
if (preview_mode) {
confirm_preview_wallpaper_callback_ = base::BindOnce(
&WallpaperControllerImpl::SetWallpaperImpl, base::Unretained(this),
account_id, wallpaper_info, image_skia, false);
reload_preview_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
base::Unretained(this), image_skia, wallpaper_info,
true, false);
reload_preview_wallpaper_callback_.Run();
} else {
SetWallpaperImpl(account_id, wallpaper_info, image_skia,
IsActiveUser(account_id));
}
}
void WallpaperControllerImpl::SaveAndSetWallpaper(const AccountId& account_id,
bool is_ephemeral,
const std::string& file_name,
const std::string& file_path,
WallpaperType type,
WallpaperLayout layout,
bool show_wallpaper,
const gfx::ImageSkia& image) {
SaveAndSetWallpaperWithCompletion(account_id, is_ephemeral, file_name,
file_path, type, layout, show_wallpaper,
image, base::DoNothing());
}
void WallpaperControllerImpl::SaveAndSetWallpaperWithCompletion(
const AccountId& account_id,
bool is_ephemeral,
const std::string& file_name,
const std::string& file_path,
WallpaperType type,
WallpaperLayout layout,
bool show_wallpaper,
const gfx::ImageSkia& image,
FilePathCallback image_saved_callback) {
if (wallpaper_controller_client_) {
wallpaper_controller_client_->GetFilesId(
account_id,
base::BindOnce(
&WallpaperControllerImpl::SaveAndSetWallpaperWithCompletionFilesId,
weak_factory_.GetWeakPtr(), account_id, is_ephemeral, file_name,
file_path, type, layout, show_wallpaper, image,
std::move(image_saved_callback)));
}
}
void WallpaperControllerImpl::SaveAndSetWallpaperWithCompletionFilesId(
const AccountId& account_id,
bool is_ephemeral,
const std::string& file_name,
const std::string& file_path,
WallpaperType type,
WallpaperLayout layout,
bool show_wallpaper,
const gfx::ImageSkia& image,
FilePathCallback image_saved_callback,
const std::string& wallpaper_files_id) {
if (image.isNull()) {
LOG(ERROR) << "The wallpaper image is empty due to a decoding failure, or "
"the client provided an empty image.";
return;
}
const std::string relative_path =
base::FilePath(wallpaper_files_id).Append(file_name).value();
WallpaperInfo info = {relative_path, layout, type, base::Time::Now(),
file_path};
if (!SetUserWallpaperInfo(account_id, is_ephemeral, info)) {
LOG(ERROR) << "Setting user wallpaper info fails. This should never happen "
"except in tests.";
}
base::FilePath wallpaper_path = GetCustomWallpaperPath(
kOriginalWallpaperSubDir, wallpaper_files_id, file_name);
const bool should_save_to_disk =
!IsEphemeralUser(account_id) && !is_ephemeral;
if (should_save_to_disk) {
wallpaper_file_manager_->SaveWallpaperToDisk(
type, custom_wallpapers_dir_, file_name, layout, image,
std::move(image_saved_callback), wallpaper_files_id);
}
if (show_wallpaper) {
ShowWallpaperImage(image, info, false,
false);
}
wallpaper_cache_map_[account_id] =
CustomWallpaperElement(wallpaper_path, image);
}
void WallpaperControllerImpl::OnWallpaperDecoded(const AccountId& account_id,
const base::FilePath& path,
const WallpaperInfo& info,
bool show_wallpaper,
const gfx::ImageSkia& image) {
if (image.isNull()) {
LOG(ERROR) << "Failed to decode user wallpaper at " << path.value()
<< " Falls back to default wallpaper. ";
wallpaper_cache_map_.erase(account_id);
SetDefaultWallpaperImpl(GetUserType(account_id), show_wallpaper,
base::DoNothing());
return;
}
wallpaper_cache_map_[account_id] = CustomWallpaperElement(path, image);
if (show_wallpaper) {
ShowWallpaperImage(image, info, false,
false);
}
}
void WallpaperControllerImpl::ReloadWallpaper(bool clear_cache) {
const bool was_one_shot_wallpaper = IsOneShotWallpaper();
const gfx::ImageSkia one_shot_wallpaper =
was_one_shot_wallpaper
? current_wallpaper_->wallpaper_info().one_shot_wallpaper
: gfx::ImageSkia();
current_wallpaper_.reset();
color_calculator_.reset();
if (clear_cache)
wallpaper_cache_map_.clear();
if (reload_override_wallpaper_callback_) {
reload_override_wallpaper_callback_.Run();
} else if (reload_preview_wallpaper_callback_) {
reload_preview_wallpaper_callback_.Run();
} else if (current_account_id_.is_valid()) {
ShowUserWallpaper(current_account_id_);
} else if (was_one_shot_wallpaper) {
ShowOneShotWallpaper(one_shot_wallpaper);
} else {
ShowSigninWallpaper();
}
}
void WallpaperControllerImpl::SetCalculatedColors(
const WallpaperCalculatedColors& calculated_colors) {
if (calculated_colors == calculated_colors_) {
return;
}
calculated_colors_ = calculated_colors;
for (auto& observer : observers_)
observer.OnWallpaperColorsChanged();
}
void WallpaperControllerImpl::ResetCalculatedColors() {
calculated_colors_.reset();
}
void WallpaperControllerImpl::CalculateWallpaperColors() {
if (color_calculator_) {
color_calculator_.reset();
}
if (!current_wallpaper_) {
return;
}
std::optional<WallpaperCalculatedColors> colors =
pref_manager_->GetCachedWallpaperColors(
current_wallpaper_->wallpaper_info().location);
if (colors) {
SetCalculatedColors(std::move(*colors));
return;
}
if (!ShouldCalculateColors()) {
ResetCalculatedColors();
return;
}
color_calculator_ =
std::make_unique<WallpaperColorCalculator>(GetWallpaper());
if (!color_calculator_->StartCalculation(base::BindOnce(
&WallpaperControllerImpl::OnColorCalculationComplete,
weak_factory_.GetWeakPtr(), current_wallpaper_->wallpaper_info()))) {
ResetCalculatedColors();
}
}
bool WallpaperControllerImpl::ShouldCalculateColors() const {
gfx::ImageSkia image = GetWallpaper();
if (image.isNull()) {
return false;
}
if (IsOobeState()) {
return true;
}
session_manager::SessionState session_state =
Shell::Get()->session_controller()->GetSessionState();
if (session_state == session_manager::SessionState::ACTIVE) {
return true;
}
return false;
}
void WallpaperControllerImpl::OnOverrideWallpaperDecoded(
const WallpaperInfo& info,
const gfx::ImageSkia& image) {
if (!is_override_wallpaper_) {
return;
}
if (image.isNull()) {
RemoveOverrideWallpaper();
return;
}
reload_override_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
weak_factory_.GetWeakPtr(), image, info,
false, true);
reload_override_wallpaper_callback_.Run();
}
bool WallpaperControllerImpl::IsDevicePolicyWallpaper() const {
return current_wallpaper_ &&
current_wallpaper_->wallpaper_info().type == WallpaperType::kDevice;
}
bool WallpaperControllerImpl::IsOneShotWallpaper() const {
return current_wallpaper_ &&
current_wallpaper_->wallpaper_info().type == WallpaperType::kOneShot;
}
bool WallpaperControllerImpl::ShouldSetDevicePolicyWallpaper() const {
if (device_policy_wallpaper_path_.empty())
return false;
return Shell::Get()->session_controller()->GetSessionState() ==
session_manager::SessionState::LOGIN_PRIMARY;
}
void WallpaperControllerImpl::SetDevicePolicyWallpaper() {
DCHECK(ShouldSetDevicePolicyWallpaper());
ReadAndDecodeWallpaper(
base::BindOnce(&WallpaperControllerImpl::OnDevicePolicyWallpaperDecoded,
weak_factory_.GetWeakPtr()),
device_policy_wallpaper_path_);
}
void WallpaperControllerImpl::OnDevicePolicyWallpaperDecoded(
const gfx::ImageSkia& image) {
if (!ShouldSetDevicePolicyWallpaper()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDevice, SetWallpaperResult::kPermissionDenied);
return;
}
if (image.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDevice, SetWallpaperResult::kDecodingError);
SetDefaultWallpaperImpl(user_manager::UserType::kRegular,
true, base::DoNothing());
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDevice, SetWallpaperResult::kSuccess);
WallpaperInfo info = {device_policy_wallpaper_path_.value(),
WALLPAPER_LAYOUT_CENTER_CROPPED,
WallpaperType::kDevice, base::Time::Now()};
ShowWallpaperImage(image, info, false,
false);
}
}
void WallpaperControllerImpl::GetInternalDisplayCompositorLock() {
if (!display::HasInternalDisplay())
return;
aura::Window* root_window =
Shell::GetRootWindowForDisplayId(display::Display::InternalDisplayId());
if (!root_window)
return;
compositor_lock_ = root_window->layer()->GetCompositor()->GetCompositorLock(
this, kCompositorLockTimeout);
}
void WallpaperControllerImpl::RepaintWallpaper() {
for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
auto* wallpaper_view =
root_window_controller->wallpaper_widget_controller()->wallpaper_view();
if (wallpaper_view)
wallpaper_view->SchedulePaint();
}
}
void WallpaperControllerImpl::HandleWallpaperInfoSyncedIn(
const AccountId& account_id,
const WallpaperInfo& info) {
if (!CanSetUserWallpaper(account_id))
return;
if (!IsActiveUser(account_id))
return;
switch (info.type) {
case WallpaperType::kCustomized:
HandleCustomWallpaperInfoSyncedIn(account_id, info);
break;
case WallpaperType::kDaily:
HandleDailyWallpaperInfoSyncedIn(account_id, info);
break;
case WallpaperType::kOnline:
HandleSettingOnlineWallpaperFromWallpaperInfo(account_id, info);
break;
case WallpaperType::kOnceGooglePhotos:
case WallpaperType::kDailyGooglePhotos:
HandleGooglePhotosWallpaperInfoSyncedIn(account_id, info);
break;
case WallpaperType::kDefault:
case WallpaperType::kPolicy:
case WallpaperType::kThirdParty:
case WallpaperType::kDevice:
case WallpaperType::kOneShot:
case WallpaperType::kOobe:
case WallpaperType::kSeaPen:
case WallpaperType::kCount:
DCHECK(false) << "Synced in an unsyncable wallpaper type";
break;
}
}
void WallpaperControllerImpl::OnGetCustomizationIdForTimeOfDayWallpaper(
const AccountId& account_id,
SetTimeOfDayWallpaperCallback set_time_of_day_wallpaper_callback,
std::optional<std::string_view> customization_id) {
const auto unit_id =
customization_id ==
wallpaper_constants::kAlternateWallpaperCustomizationId
? wallpaper_constants::kAlternateTimeOfDayWallpaperUnitId
: wallpaper_constants::kDefaultTimeOfDayWallpaperUnitId;
DVLOG(1) << __func__
<< " customization_id: " << customization_id.value_or("null")
<< " unit_id: " << unit_id;
OnlineWallpaperVariantInfoFetcher::FetchParamsCallback on_fetch =
base::BindOnce(
&WallpaperControllerImpl::OnWallpaperVariantsFetched,
set_wallpaper_weak_factory_.GetWeakPtr(), WallpaperType::kOnline,
base::BindOnce(std::move(set_time_of_day_wallpaper_callback),
unit_id));
variant_info_fetcher_.FetchTimeOfDayWallpaper(account_id, unit_id,
std::move(on_fetch));
}
void WallpaperControllerImpl::OnTimeOfDayWallpaperSetAfterOobe(
const uint64_t unit_id,
const bool success) {
wallpaper_metrics_manager_->LogSettingTimeOfDayWallpaperAfterOobe(unit_id,
success);
}
void WallpaperControllerImpl::OnDailyRefreshWallpaperUpdated(
RefreshWallpaperCallback callback,
bool success) {
if (success) {
auto first_check_time = base::Time::Now();
auto second_check_time = first_check_time + base::Hours(1);
if (features::IsWallpaperFastRefreshEnabled()) {
first_check_time = base::Time::Now() + base::Minutes(1);
second_check_time = first_check_time + base::Minutes(1);
}
DVLOG(1) << __func__
<< " updating check times - first_check_time=" << first_check_time
<< " - second_check_time=" << second_check_time;
daily_refresh_scheduler_->SetCustomStartTime(
TimeOfDay::FromTime(first_check_time));
daily_refresh_scheduler_->SetCustomEndTime(
TimeOfDay::FromTime(second_check_time));
}
std::move(callback).Run(success);
if (!daily_refresh_observation_.IsObserving()) {
daily_refresh_observation_.Observe(daily_refresh_scheduler_.get());
}
}
void WallpaperControllerImpl::SetDailyRefreshCollectionId(
const AccountId& account_id,
const std::string& collection_id) {
if (!CanSetUserWallpaper(account_id)) {
LOG(WARNING) << "Invalid request to set daily refresh collection id";
return;
}
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info))
return;
if (!collection_id.empty()) {
info.type = WallpaperType::kDaily;
info.collection_id = collection_id;
}
if (collection_id.empty() && info.type == WallpaperType::kDaily) {
info.type = WallpaperType::kOnline;
}
SetUserWallpaperInfo(account_id, info);
}
std::string WallpaperControllerImpl::GetDailyRefreshCollectionId(
const AccountId& account_id) const {
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info))
return std::string();
if (info.type != WallpaperType::kDaily)
return std::string();
return info.collection_id;
}
void WallpaperControllerImpl::SyncLocalAndRemotePrefs(
const AccountId& account_id) {
WallpaperInfo synced_info;
WallpaperInfo local_info;
if (!pref_manager_->GetSyncedWallpaperInfo(account_id, &synced_info)) {
return;
}
if (!pref_manager_->GetLocalWallpaperInfo(account_id, &local_info)) {
HandleWallpaperInfoSyncedIn(account_id, synced_info);
return;
}
if (!synced_info.MatchesSelection(local_info) &&
synced_info.date < local_info.date &&
local_info.type == WallpaperType::kCustomized) {
base::FilePath source = GetCustomWallpaperDir(kOriginalWallpaperSubDir)
.Append(local_info.location);
SaveWallpaperToDriveFsAndSyncInfo(account_id, source);
return;
}
if (!WallpaperPrefManager::ShouldSyncIn(synced_info, local_info,
IsOobeState())) {
return;
}
HandleWallpaperInfoSyncedIn(account_id, synced_info);
}
const AccountId& WallpaperControllerImpl::CurrentAccountId() const {
return current_account_id_;
}
bool WallpaperControllerImpl::IsDailyRefreshEnabled() const {
return !GetDailyRefreshCollectionId(GetActiveAccountId()).empty();
}
bool WallpaperControllerImpl::IsDailyGooglePhotosWallpaperSelected() {
auto info = GetActiveUserWallpaperInfo();
return (info && info->type == WallpaperType::kDailyGooglePhotos);
}
bool WallpaperControllerImpl::IsGooglePhotosWallpaperSet() const {
auto info = GetActiveUserWallpaperInfo();
return (info && info->type == WallpaperType::kOnceGooglePhotos);
}
void WallpaperControllerImpl::UpdateDailyRefreshWallpaper(
RefreshWallpaperCallback callback) {
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
if (!IsDailyRefreshEnabled() && !IsDailyGooglePhotosWallpaperSelected()) {
std::move(callback).Run(false);
return;
}
daily_refresh_observation_.Reset();
auto on_done =
base::BindOnce(&WallpaperControllerImpl::OnDailyRefreshWallpaperUpdated,
weak_factory_.GetWeakPtr(), std::move(callback));
AccountId account_id = GetActiveAccountId();
WallpaperInfo info;
if (wallpaper_controller_client_ && GetUserWallpaperInfo(account_id, &info)) {
if (info.type == WallpaperType::kDailyGooglePhotos) {
SetGooglePhotosWallpaper(
GooglePhotosWallpaperParams(
account_id, info.collection_id,
true, info.layout,
false, std::nullopt),
std::move(on_done));
} else {
DCHECK_EQ(info.type, WallpaperType::kDaily);
OnlineWallpaperVariantInfoFetcher::FetchParamsCallback fetch_callback =
base::BindOnce(&WallpaperControllerImpl::OnWallpaperVariantsFetched,
set_wallpaper_weak_factory_.GetWeakPtr(), info.type,
std::move(on_done));
if (!variant_info_fetcher_.FetchDailyWallpaper(
account_id, info, std::move(fetch_callback))) {
NOTREACHED() << "Failed to initiate daily wallpaper fetch";
}
}
} else {
std::move(on_done).Run(false);
}
}
base::FilePath WallpaperControllerImpl::GetUserGooglePhotosWallpaperDir(
const AccountId& account_id) const {
CHECK(account_id.HasAccountIdKey());
CHECK(!google_photos_wallpapers_dir_.empty());
return google_photos_wallpapers_dir_.Append(account_id.GetAccountIdKey());
}
base::FilePath WallpaperControllerImpl::GetUserSeaPenWallpaperDir(
const AccountId& account_id) const {
CHECK(account_id.HasAccountIdKey());
CHECK(!sea_pen_wallpaper_dir_.empty());
return sea_pen_wallpaper_dir_.Append(account_id.GetAccountIdKey());
}
void WallpaperControllerImpl::CheckGooglePhotosStaleness(
const AccountId& account_id,
const WallpaperInfo& info) {
DCHECK_EQ(info.type, WallpaperType::kOnceGooglePhotos);
wallpaper_controller_client_->FetchGooglePhotosPhoto(
account_id, info.location,
base::BindOnce(&WallpaperControllerImpl::HandleGooglePhotosStalenessCheck,
set_wallpaper_weak_factory_.GetWeakPtr(), account_id));
}
void WallpaperControllerImpl::HandleGooglePhotosStalenessCheck(
const AccountId& account_id,
ash::personalization_app::mojom::GooglePhotosPhotoPtr photo,
bool success) {
if (!success)
return;
if (!photo) {
if (account_id.HasAccountIdKey()) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(base::IgnoreResult(&base::DeletePathRecursively),
GetUserGooglePhotosWallpaperDir(account_id)));
}
SetDefaultWallpaper(account_id, true, base::DoNothing());
}
}
void WallpaperControllerImpl::SaveWallpaperToDriveFsAndSyncInfo(
const AccountId& account_id,
const base::FilePath& origin_path) {
if (!wallpaper_controller_client_)
return;
if (!wallpaper_controller_client_->IsWallpaperSyncEnabled(account_id))
return;
drivefs_delegate_->SaveWallpaper(
account_id, origin_path,
base::BindOnce(&WallpaperControllerImpl::WallpaperSavedToDriveFS,
weak_factory_.GetWeakPtr(), account_id));
}
void WallpaperControllerImpl::WallpaperSavedToDriveFS(
const AccountId& account_id,
bool success) {
if (!success)
return;
WallpaperInfo local_info;
CHECK(pref_manager_->GetLocalWallpaperInfo(account_id, &local_info));
pref_manager_->SetSyncedWallpaperInfo(account_id, local_info);
}
void WallpaperControllerImpl::HandleCustomWallpaperInfoSyncedIn(
const AccountId& account_id,
const WallpaperInfo& wallpaper_info) {
drivefs_delegate_->GetWallpaperModificationTime(
account_id,
base::BindOnce(
&WallpaperControllerImpl::OnGetDriveFsWallpaperModificationTime,
weak_factory_.GetWeakPtr(), account_id, wallpaper_info));
}
void WallpaperControllerImpl::OnGetDriveFsWallpaperModificationTime(
const AccountId& account_id,
const WallpaperInfo& wallpaper_info,
base::Time modification_time) {
if (modification_time.is_null() || modification_time < wallpaper_info.date) {
DVLOG(1) << "Skip syncing custom wallpaper from DriveFS. Wallpaper "
"modification_time: "
<< modification_time;
drivefs_delegate_->WaitForWallpaperChange(
account_id,
base::BindOnce(&WallpaperControllerImpl::OnDriveFsWallpaperChange,
weak_factory_.GetWeakPtr(), account_id));
return;
}
base::FilePath path_in_prefs = base::FilePath(wallpaper_info.location);
std::string file_name = path_in_prefs.BaseName().value();
std::string file_path = wallpaper_info.user_file_path;
drivefs_delegate_->DownloadAndDecodeWallpaper(
account_id,
base::BindOnce(&WallpaperControllerImpl::SaveAndSetWallpaper,
weak_factory_.GetWeakPtr(), account_id,
IsEphemeralUser(account_id), file_name, file_path,
WallpaperType::kCustomized, wallpaper_info.layout,
true));
}
void WallpaperControllerImpl::OnDriveFsWallpaperChange(
const AccountId& account_id,
bool success) {
if (success) {
SyncLocalAndRemotePrefs(account_id);
}
}
void WallpaperControllerImpl::HandleDailyWallpaperInfoSyncedIn(
const AccountId& account_id,
const WallpaperInfo& info) {
DCHECK(info.type == WallpaperType::kDaily);
std::string old_collection_id = GetDailyRefreshCollectionId(account_id);
if (info.collection_id == old_collection_id)
return;
OnlineWallpaperVariantInfoFetcher::FetchParamsCallback callback =
base::BindOnce(&WallpaperControllerImpl::OnWallpaperVariantsFetched,
weak_factory_.GetWeakPtr(), info.type, base::DoNothing());
if (!variant_info_fetcher_.FetchDailyWallpaper(account_id, info,
std::move(callback))) {
NOTREACHED() << "Fetch of daily wallpaper info failed.";
}
}
void WallpaperControllerImpl::HandleGooglePhotosWallpaperInfoSyncedIn(
const AccountId& account_id,
const WallpaperInfo& info) {
bool daily_refresh_enabled = info.type == WallpaperType::kDailyGooglePhotos;
if (daily_refresh_enabled) {
WallpaperInfo old_info;
if (GetUserWallpaperInfo(account_id, &old_info) &&
old_info.collection_id != info.collection_id) {
SetGooglePhotosWallpaper(
GooglePhotosWallpaperParams(
account_id, info.collection_id,
true, info.layout,
false, std::nullopt),
base::DoNothing());
}
} else {
SetGooglePhotosWallpaper(GooglePhotosWallpaperParams(
account_id, info.location,
false, info.layout,
false, info.dedup_key),
base::DoNothing());
}
}
void WallpaperControllerImpl::HandleSettingOnlineWallpaperFromWallpaperInfo(
const AccountId& account_id,
const WallpaperInfo& info) {
DCHECK(IsOnlineWallpaper(info.type));
OnlineWallpaperVariantInfoFetcher::FetchParamsCallback callback =
base::BindOnce(&WallpaperControllerImpl::OnWallpaperVariantsFetched,
set_wallpaper_weak_factory_.GetWeakPtr(), info.type,
base::DoNothing());
variant_info_fetcher_.FetchOnlineWallpaper(account_id, info,
std::move(callback));
}
void WallpaperControllerImpl::CleanUpBeforeSettingUserWallpaperInfo(
const AccountId& account_id,
const WallpaperInfo& info) {
std::vector<base::FilePath> directories_to_remove;
if (account_id.HasAccountIdKey() &&
info.type != WallpaperType::kOnceGooglePhotos &&
info.type != WallpaperType::kDailyGooglePhotos) {
if (google_photos_wallpapers_dir_.empty()) {
CHECK_IS_TEST();
} else {
directories_to_remove.push_back(
GetUserGooglePhotosWallpaperDir(account_id));
}
}
if (account_id.HasAccountIdKey() && info.type != WallpaperType::kSeaPen) {
if (sea_pen_wallpaper_dir_.empty()) {
CHECK_IS_TEST();
} else {
directories_to_remove.push_back(GetUserSeaPenWallpaperDir(account_id));
}
}
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DeleteWallpaperInList, std::move(directories_to_remove)));
}
bool WallpaperControllerImpl::IsOobeState() const {
session_manager::SessionState session_state =
Shell::Get()->session_controller()->GetSessionState();
const bool is_default_oobe_flow =
session_state == session_manager::SessionState::OOBE;
const bool is_add_person_flow =
session_state == session_manager::SessionState::LOGIN_PRIMARY &&
oobe_state_ != OobeDialogState::HIDDEN;
DVLOG(1) << __func__ << " is_default_oobe_flow=" << is_default_oobe_flow
<< " is_add_person_flow=" << is_add_person_flow;
return is_default_oobe_flow || is_add_person_flow;
}
const ScheduledFeature& WallpaperControllerImpl::GetScheduleForOnlineWallpaper(
const std::string& collection_id) const {
if (::ash::IsTimeOfDayWallpaper(collection_id) &&
features::IsTimeOfDayWallpaperEnabled()) {
return *time_of_day_scheduler_;
} else {
return *Shell::Get()->dark_light_mode_controller();
}
}
}