// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wallpaper/wallpaper_controller_impl.h"
#include <string>
#include <string_view>
#include "ash/constants/ash_features.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_info_migrator.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_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/no_destructor.h"
#include "base/rand_util.h"
#include "base/ranges/algorithm.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/constants/chromeos_features.h"
#include "components/account_id/account_id.h"
#include "components/prefs/pref_service.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 {
// Global to hold a WallpaperPrefManager for testing in `Create`.
std::unique_ptr<WallpaperPrefManager> g_test_pref_manager;
// Global to hold a WallpaperImageDownloader for testing in `Create`.
std::unique_ptr<WallpaperImageDownloader> g_test_image_downloader;
// The file name of the policy wallpaper.
constexpr char kPolicyWallpaperFile[] = "policy-controlled.jpeg";
// How long to wait reloading the wallpaper after the display size has changed.
constexpr base::TimeDelta kWallpaperReloadDelay = base::Milliseconds(100);
// How long to wait for resizing of the the wallpaper.
constexpr base::TimeDelta kCompositorLockTimeout = base::Milliseconds(750);
// The color of the wallpaper if no other wallpaper images are available.
constexpr SkColor kDefaultWallpaperColor = SK_ColorGRAY;
// The color of the Oobe wallpaper if no other wallpaper images are available.
constexpr SkColor kOobeWallpaperColor = SK_ColorWHITE;
// The paths of wallpaper directories.
base::FilePath& GlobalUserDataDir() {
static base::NoDestructor<base::FilePath> dir_user_data;
return *dir_user_data;
}
base::FilePath& GlobalChromeOSWallpapersDir() {
static base::NoDestructor<base::FilePath> dir_chrome_os_wallpapers;
return *dir_chrome_os_wallpapers;
}
base::FilePath& GlobalChromeOSCustomWallpapersDir() {
static base::NoDestructor<base::FilePath> dir_chrome_os_custom_wallpapers;
return *dir_chrome_os_custom_wallpapers;
}
base::FilePath& GlobalChromeOSGooglePhotosWallpapersDir() {
static base::NoDestructor<base::FilePath>
dir_chrome_os_google_photos_wallpapers;
return *dir_chrome_os_google_photos_wallpapers;
}
base::FilePath& GlobalChromeOSSeaPenWallpaperDir() {
static base::NoDestructor<base::FilePath> dir_chrome_os_sea_pen_wallpaper;
return *dir_chrome_os_sea_pen_wallpaper;
}
void SetGlobalUserDataDir(const base::FilePath& path) {
base::FilePath& global_path = GlobalUserDataDir();
global_path = path;
}
void SetGlobalChromeOSWallpapersDir(const base::FilePath& path) {
base::FilePath& global_path = GlobalChromeOSWallpapersDir();
global_path = path;
}
void SetGlobalChromeOSGooglePhotosWallpapersDir(const base::FilePath& path) {
base::FilePath& global_path = GlobalChromeOSGooglePhotosWallpapersDir();
global_path = path;
}
void SetGlobalChromeOSSeaPenWallpaperDir(const base::FilePath& path) {
base::FilePath& global_path = GlobalChromeOSSeaPenWallpaperDir();
global_path = path;
}
void SetGlobalChromeOSCustomWallpapersDir(const base::FilePath& path) {
base::FilePath& global_path = GlobalChromeOSCustomWallpapersDir();
global_path = path;
}
base::FilePath GetUserGooglePhotosWallpaperDir(const AccountId& account_id) {
DCHECK(account_id.HasAccountIdKey());
return GlobalChromeOSGooglePhotosWallpapersDir().Append(
account_id.GetAccountIdKey());
}
base::FilePath GetUserSeaPenWallpaperDir(const AccountId& account_id) {
DCHECK(account_id.HasAccountIdKey());
const base::FilePath& global_sea_pen_dir = GlobalChromeOSSeaPenWallpaperDir();
DCHECK(!global_sea_pen_dir.empty());
return global_sea_pen_dir.Append(account_id.GetAccountIdKey());
}
// Returns wallpaper subdirectory name for current resolution.
std::string GetCustomWallpaperSubdirForCurrentResolution() {
WallpaperResolution resolution = GetAppropriateResolution();
return resolution == WallpaperResolution::kSmall ? kSmallWallpaperSubDir
: kLargeWallpaperSubDir;
}
// Creates a 1x1 solid color image.
gfx::ImageSkia CreateSolidColorWallpaper(SkColor color) {
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(color);
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
}
// Deletes a list of wallpaper files in |file_list|.
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();
}
}
// Checks if kiosk app is running. Note: it returns false either when there's
// no active user (e.g. at login screen), or the active user is not kiosk.
bool IsInKioskMode() {
std::optional<user_manager::UserType> active_user_type =
Shell::Get()->session_controller()->GetUserType();
// |active_user_type| is empty when there's no active user.
return active_user_type &&
*active_user_type == user_manager::UserType::kKioskApp;
}
// Returns the currently active user session (at index 0).
const UserSession* GetActiveUserSession() {
return Shell::Get()->session_controller()->GetUserSession(/*user index=*/0);
}
AccountId GetActiveAccountId() {
const UserSession* const session = GetActiveUserSession();
DCHECK(session);
return session->user_info.account_id;
}
// Checks if |account_id| is the current active user.
bool IsActiveUser(const AccountId& account_id) {
const UserSession* const session = GetActiveUserSession();
return session && session->user_info.account_id == account_id;
}
// Returns the type of the user with the specified |id| or kRegular.
user_manager::UserType GetUserType(const AccountId& id) {
const UserSession* user_session =
Shell::Get()->session_controller()->GetUserSessionByAccountId(id);
// If we can't match the account with a session, we can't safely continue.
if (!user_session) {
// TODO(crbug.com/1329256): Change tests that hit this codepath to sign in
// users first if they have an active session so that this can be changed to
// a CHECK.
LOG(ERROR) << "Cannot resolve user. Assuming regular. This should only "
"happen in tests";
return user_manager::UserType::kRegular;
}
return user_session->user_info.type;
}
// Gets |account_id|'s custom wallpaper at |wallpaper_path|. Falls back to the
// original custom wallpaper. Verifies that the returned path exists. If a valid
// path cannot be found, returns an empty FilePath. Must run on wallpaper
// sequenced worker thread.
base::FilePath PathWithFallback(const AccountId& account_id,
const WallpaperInfo& info,
const base::FilePath& wallpaper_path) {
if (base::PathExists(wallpaper_path))
return wallpaper_path;
// Falls back to the original file if the file with correct resolution does
// not exist. This may happen when the original custom wallpaper is small or
// browser shutdown before resized wallpaper saved.
base::FilePath valid_path =
WallpaperControllerImpl::GetCustomWallpaperDir(kOriginalWallpaperSubDir)
.Append(info.location);
return base::PathExists(valid_path) ? valid_path : base::FilePath();
}
// Deletes the user-specific directory inside the Google Photos cache
// directory. Only call this by posting it to `sequenced_task_runner_` with no
// delay to ensure that file IO is called in a well defined order. This avoids
// accidentally deleting the cache immediately after creating it, etc.
void DeleteGooglePhotosCache(const AccountId& account_id) {
// Don't bother deleting for anyone without an AccountId, since they don't
// have a way to set Google Photos Wallpapers. Guest accounts may not be able
// to call `AccountId::GetAccountIdKey()`, so we can't compute a path for
// them.
if (account_id.HasAccountIdKey()) {
base::DeletePathRecursively(GetUserGooglePhotosWallpaperDir(account_id));
}
}
scoped_refptr<base::RefCountedMemory> EncodeAndResizeImage(
gfx::ImageSkia image) {
auto resized = WallpaperResizer::GetResizedImage(image,
/*max_size_in_dips=*/1024);
scoped_refptr<base::RefCountedMemory> jpg_bytes = new base::RefCountedBytes();
std::vector<uint8_t> jpg_buffer;
// Conversion quality between 0 - 100. Manually tested to use 90 for good
// performance with reasonable quality.
gfx::JPEG1xEncodedDataFromImage(gfx::Image(resized), /*quality=*/90,
&jpg_buffer);
jpg_bytes = base::RefCountedBytes::TakeVector(&jpg_buffer);
return jpg_bytes;
}
// Selects the online wallpaper variant to show and specifies it in the
// returned `WallpaperInfo`. Returns nullptr on failure.
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);
}
} // namespace
// static
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));
}
// static
void WallpaperControllerImpl::SetWallpaperPrefManagerForTesting(
std::unique_ptr<WallpaperPrefManager> pref_manager) {
g_test_pref_manager.swap(pref_manager);
}
// static
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>();
}
WallpaperControllerImpl::~WallpaperControllerImpl() {
Shell::Get()->display_manager()->RemoveDisplayManagerObserver(this);
Shell::Get()->RemoveShellObserver(this);
// Per ash/shell.cc, wallpaper_controller_impl outlives
// login_screen_controller. Therefore don't remove the observer from
// data_dispatcher on destruction.
}
// static
base::FilePath WallpaperControllerImpl::GetCustomWallpaperPath(
const std::string& sub_dir,
const std::string& wallpaper_files_id,
const std::string& file_name) {
base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
return custom_wallpaper_path.Append(wallpaper_files_id).Append(file_name);
}
// static
base::FilePath WallpaperControllerImpl::GetCustomWallpaperDir(
const std::string& sub_dir) {
DCHECK(!GlobalChromeOSCustomWallpapersDir().empty());
return GlobalChromeOSCustomWallpapersDir().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() {
// The slower initial animation is only applicable if:
// 1) It's the first run after system boot, not after user sign-out.
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kFirstExecAfterBoot)) {
return false;
}
// 2) It's at the login screen.
if (Shell::Get()->session_controller()->IsActiveUserSessionStarted() ||
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kLoginManager)) {
return false;
}
// 3) It's the first wallpaper being shown, not for the switching between
// multiple user pods.
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) {
// Prevent showing other wallpapers if there is an override wallpaper.
if (is_override_wallpaper_ && !is_override) {
return;
}
// Ignore show wallpaper requests during preview mode. This could happen if a
// custom wallpaper previously set on another device is being synced.
if (confirm_preview_wallpaper_callback_ && !preview_mode)
return;
if (preview_mode) {
DVLOG(1) << __func__ << " preview_mode=true";
for (auto& observer : observers_)
observer.OnWallpaperPreviewStarted();
}
// 1x1 wallpaper should be stretched to fill the entire screen.
// (WALLPAPER_LAYOUT_TILE also serves this purpose.)
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, /*compare_layouts=*/true, info.layout)) {
VLOG(1) << "Wallpaper is already loaded";
return;
}
// Cancel any in-flight color calculation because we have a new wallpaper.
if (color_calculator_) {
color_calculator_.reset();
}
is_first_wallpaper_ = !current_wallpaper_;
current_wallpaper_ = std::make_unique<WallpaperResizer>(
image, GetMaxDisplaySizeInNative(), info);
// `this` owns `current_wallpaper_` and therefore can use `base::Unretained`.
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::GetScreen()->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())) {
// No wallpaper has been set, or the first wallpaper is still animating.
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()) {
// Fallback to default if the path is 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);
}
void WallpaperControllerImpl::Init(
const base::FilePath& user_data_path,
const base::FilePath& chromeos_wallpapers_path,
const base::FilePath& chromeos_custom_wallpapers_path,
const base::FilePath& device_policy_wallpaper_path) {
SetGlobalUserDataDir(user_data_path);
SetGlobalChromeOSWallpapersDir(chromeos_wallpapers_path);
SetGlobalChromeOSGooglePhotosWallpapersDir(
chromeos_wallpapers_path.Append("google_photos/"));
SetGlobalChromeOSSeaPenWallpaperDir(chromeos_wallpapers_path.Append(
wallpaper_constants::kSeaPenWallpaperDirName));
SetGlobalChromeOSCustomWallpapersDir(chromeos_custom_wallpapers_path);
SetDevicePolicyWallpaperPath(device_policy_wallpaper_path);
}
bool WallpaperControllerImpl::CanSetUserWallpaper(
const AccountId& account_id) const {
// There is no visible wallpaper in kiosk mode.
if (IsInKioskMode()) {
return false;
}
// Don't allow user wallpapers while policy is in effect.
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);
// Return early to skip the work of decoding.
std::move(callback).Run(/*success=*/false);
return;
}
// Invalidate weak ptrs to cancel prior requests to set wallpaper.
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(/*success=*/false);
return;
}
for (auto& observer : observers_) {
observer.OnUserSetWallpaper(account_id);
}
wallpaper_metrics_manager_->LogWallpaperResult(WallpaperType::kCustomized,
SetWallpaperResult::kSuccess);
// Run callback before finishing setting the image. This is the same timing of
// success callback, then |WallpaperControllerObserver::OnWallpaperChanged|,
// when setting online wallpaper and simplifies the logic in observers.
std::move(callback).Run(/*success=*/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,
/*show_wallpaper=*/false, image);
reload_preview_wallpaper_callback_ = base::BindRepeating(
&WallpaperControllerImpl::ShowWallpaperImage, base::Unretained(this),
image,
WallpaperInfo{/*in_location=*/std::string(), layout,
WallpaperType::kCustomized, base::Time::Now(), file_path},
/*preview_mode=*/true, /*is_override=*/false);
// Show the preview wallpaper.
reload_preview_wallpaper_callback_.Run();
} else {
SaveAndSetWallpaperWithCompletion(
account_id, IsEphemeralUser(account_id), file_name, file_path,
WallpaperType::kCustomized, layout,
/*show_wallpaper=*/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(/*success=*/false);
return;
}
std::unique_ptr<WallpaperInfo> new_info = CreateOnlineWallpaperInfo(
params, GetScheduleForOnlineWallpaper(params.collection_id), __func__);
if (!new_info) {
std::move(callback).Run(/*success=*/false);
return;
}
if (current_wallpaper_ &&
current_wallpaper_->wallpaper_info().MatchesAsset(*new_info)) {
DVLOG(1) << "Detected no change in online wallpaper";
std::move(callback).Run(/*success=*/true);
// Fires resized signal to
// `PersonalizationAppWallpaperProviderImpl::OnWallpaperResized` to tell the
// UI to clear the loading state.
for (auto& observer : observers_) {
observer.OnWallpaperResized();
}
return;
}
// Invalidate weak ptrs to cancel prior requests to set wallpaper.
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
for (auto& observer : observers_)
observer.OnOnlineWallpaperSet(params);
online_wallpaper_manager_.GetOnlineWallpaper(
GlobalChromeOSWallpapersDir(), 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(/*success=*/false);
return;
}
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
if (params.daily_refresh_enabled) {
// If `params.id` is empty, then we are disabling Daily Refresh, so we set
// the currently shown wallpaper as a `WallpaperType::kOnceGooglePhotos`
// Wallpaper.
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 daily refresh is being enabled.
if (!album_id.empty()) {
info.type = WallpaperType::kDailyGooglePhotos;
info.collection_id = album_id;
}
// If Daily Refresh is disabled without selecting another wallpaper, we should
// keep the current wallpaper and change to type
// `WallpaperType::kOnceGooglePhotos`, so daily refreshes stop.
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,
SetWallpaperCallback callback) {
OnlineWallpaperVariantInfoFetcher::FetchParamsCallback on_fetch =
base::BindOnce(&WallpaperControllerImpl::OnWallpaperVariantsFetched,
set_wallpaper_weak_factory_.GetWeakPtr(),
WallpaperType::kOnline, std::move(callback));
variant_info_fetcher_.FetchTimeOfDayWallpaper(
account_id, wallpaper_constants::kDefaultTimeOfDayWallpaperUnitId,
std::move(on_fetch));
}
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(/*success=*/false);
return;
}
RemoveUserWallpaper(account_id, /*on_removed=*/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), /*show_wallpaper=*/true,
std::move(callback));
} else {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDefault, SetWallpaperResult::kSuccess);
std::move(callback).Run(/*success=*/true);
}
}
base::FilePath WallpaperControllerImpl::GetDefaultWallpaperPath(
user_manager::UserType user_type) {
const bool use_small =
(GetAppropriateResolution() == WallpaperResolution::kSmall);
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// The wallpaper is determined in the following order:
// Guest wallpaper, child wallpaper, customized default wallpaper, and regular
// default wallpaper.
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;
// If the current wallpaper has type `WallpaperType::kDefault`, the new
// customized default wallpaper should be shown immediately to update the
// screen. It shouldn't replace wallpapers of other types.
bool show_wallpaper = (GetWallpaperType() == WallpaperType::kDefault);
// Customized default wallpapers are subject to the same restrictions as other
// default wallpapers, e.g. they should not be set during guest sessions.
// This should ONLY be called from OOBE where there should not be an active
// session.
auto* active_user_session = GetActiveUserSession();
// Login does not have an active session and the expected behavior is that of
// a regular user.
user_manager::UserType user_type = user_manager::UserType::kRegular;
if (active_user_session) {
// We expect that this finishes before the user has logged in.
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) {
// There is no visible wallpaper in kiosk mode.
if (IsInKioskMode())
return;
DCHECK(user_type == user_manager::UserType::kRegular ||
user_type == user_manager::UserType::kPublicAccount);
// Updates the screen only when the user with this account_id has logged in.
const bool show_wallpaper = IsActiveUser(account_id);
if (bypass_decode_for_testing_) {
OnPolicyWallpaperDecoded(account_id, user_type, show_wallpaper,
CreateSolidColorWallpaper(kDefaultWallpaperColor));
return;
}
// Invalidate weak ptrs to cancel prior requests to set wallpaper.
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);
SaveAndSetWallpaper(
account_id, user_type == user_manager::UserType::kPublicAccount,
kPolicyWallpaperFile, /*file_path=*/"", 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()) {
// If the device wallpaper policy is cleared, the wallpaper should revert to
// the wallpaper of the current user with the large pod in the users list in
// the login screen. If there is no such user, use the first user in the
// users list.
// TODO(xdai): Get the account id from the session controller and then call
// ShowUserWallpaper() to display it.
}
}
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,
/*file_path=*/"", 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);
// Return early to skip the work of decoding.
std::move(callback).Run(/*success=*/false);
return;
}
sea_pen_wallpaper_manager_.TouchFile(account_id, image_id);
// Invalidate weak ptrs to cancel prior requests to set wallpaper.
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();
// Ensure shield is applied after confirming the preview wallpaper.
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(/*clear_cache=*/false);
for (auto& observer : observers_)
observer.OnWallpaperPreviewEnded();
}
void WallpaperControllerImpl::UpdateCurrentWallpaperLayout(
const AccountId& account_id,
WallpaperLayout layout) {
// This method has a very specific use case: the user should be active and
// have a custom wallpaper.
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_type == user_manager::UserType::kKioskApp ||
user_type == user_manager::UserType::kWebKioskApp) {
return;
}
if (ShouldSetDevicePolicyWallpaper()) {
SetDevicePolicyWallpaper();
return;
}
WallpaperInfo info;
if (!GetUserWallpaperInfo(account_id, &info)) {
if (!SetDefaultWallpaperInfo(account_id, base::Time::Min()))
return;
GetUserWallpaperInfo(account_id, &info);
}
// For ephemeral users, the cache is the only place to access their wallpaper
// because it is not saved to disk. If the image doesn't exist in cache, it
// means the user's wallpaper type is default (i.e. the user never sets their
// own wallpaper), and it's a bug if it's not.
//
// For regular users, the image will be read from disk if the cache is not
// hit (e.g. when the first time the wallpaper is shown on login screen).
gfx::ImageSkia user_wallpaper;
if (GetWallpaperFromCache(account_id, &user_wallpaper)) {
ShowWallpaperImage(user_wallpaper, info, /*preview_mode=*/false,
/*is_override=*/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, /*show_wallpaper=*/true,
base::DoNothing());
return;
}
if (IsOnlineWallpaper(info.type) ||
info.type == WallpaperType::kOnceGooglePhotos ||
info.type == WallpaperType::kDailyGooglePhotos ||
info.type == WallpaperType::kSeaPen) {
// Load wallpaper according to WallpaperInfo.
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);
// Do not try to load the wallpaper if the path is the same, since loading
// could still be in progress. We ignore the existence of the image.
base::FilePath cached_wallpaper_path;
if (GetPathFromCache(account_id, &cached_wallpaper_path) &&
cached_wallpaper_path == wallpaper_path) {
return;
}
// Set the new path and reset the existing image - the image will be
// added once it becomes available.
wallpaper_cache_map_[account_id] =
CustomWallpaperElement(wallpaper_path, gfx::ImageSkia());
sequenced_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&PathWithFallback, account_id, info, wallpaper_path),
base::BindOnce(&WallpaperControllerImpl::StartDecodeFromPath,
weak_factory_.GetWeakPtr(), account_id, user_type, info,
/*show_wallpaper=*/true));
}
void WallpaperControllerImpl::ShowSigninWallpaper() {
current_account_id_ = EmptyAccountId();
if (ShouldSetDevicePolicyWallpaper()) {
SetDevicePolicyWallpaper();
return;
}
if (IsOobeState()) {
ShowOobeWallpaper();
return;
}
// If we don't have a user, use the regular default.
SetDefaultWallpaperImpl(user_manager::UserType::kRegular,
/*show_wallpaper=*/true, base::DoNothing());
}
void WallpaperControllerImpl::ShowOneShotWallpaper(
const gfx::ImageSkia& image) {
const WallpaperInfo info = {/*in_location=*/std::string(),
WallpaperLayout::WALLPAPER_LAYOUT_STRETCH,
WallpaperType::kOneShot, base::Time::Now()};
ShowWallpaperImage(image, info, /*preview_mode=*/false,
/*is_override=*/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 = {/*in_location=*/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();
// Forget current wallpaper data.
current_wallpaper_.reset();
ReloadWallpaper(/*clear_cache=*/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;
// Updates the screen only when the user has logged in.
const bool show_wallpaper =
Shell::Get()->session_controller()->IsActiveUserSessionStarted();
// Removes the wallpaper info so that the user is no longer policy controlled,
// otherwise setting default wallpaper is not allowed.
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 =
base::ranges::find(variants, backdrop::Image::IMAGE_TYPE_PREVIEW_MODE,
&OnlineWallpaperVariant::type);
// No image with |backdrop::Image::IMAGE_TYPE_PREVIEW_MODE|, fallback to
// |resized|.
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(
GlobalChromeOSWallpapersDir(), 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::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(), /*clear_cache=*/false));
}
}
void WallpaperControllerImpl::OnRootWindowAdded(aura::Window* root_window) {
// The wallpaper hasn't been set yet.
if (wallpaper_mode_ == WALLPAPER_NONE)
return;
// Handle resolution change for "built-in" images.
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(/*clear_cache=*/true);
}
UpdateWallpaperForRootWindow(root_window, /*lock_state_changed=*/false,
/*new_root=*/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::SaveMigratedWallpaperInfo(
const std::optional<WallpaperInfo>& migrated_info) {
AccountId account_id = GetActiveAccountId();
if (migrated_info) {
// Migration succeeded, save the migrated info.
pref_manager_->SetLocalWallpaperInfo(account_id, *migrated_info);
} else {
LOG(ERROR) << "Wallpaper info migration failed for account " << account_id;
}
HandleWallpaperInfoAfterMigration(account_id);
}
void WallpaperControllerImpl::HandleWallpaperInfoAfterMigration(
const AccountId& account_id) {
WallpaperInfo local_info;
bool has_local_info =
pref_manager_->GetLocalWallpaperInfo(account_id, &local_info);
bool should_set_time_of_day_wallpaper =
IsOobeState() && 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.";
// Sets the time of day wallpaper as the default wallpaper on active user
// pref changed during OOBE flow.
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);
}
}
// Starts watching for sync pref changes.
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(
Shell::Get()->session_controller()->GetActivePrefService());
pref_change_registrar_->Add(
WallpaperPrefManager::GetSyncPrefName(),
base::BindRepeating(&WallpaperControllerImpl::SyncLocalAndRemotePrefs,
weak_factory_.GetWeakPtr(), account_id));
SyncLocalAndRemotePrefs(account_id);
}
// Sends signal for daily refresh check.
OnCheckpointChanged(daily_refresh_scheduler_.get(),
daily_refresh_scheduler_->current_checkpoint());
}
void WallpaperControllerImpl::HandleSyncedWallpaperInfoAfterMigration(
const AccountId& account_id,
const std::optional<WallpaperInfo>& synced_info) {
if (!synced_info) {
LOG(WARNING) << __func__
<< " Unable to migrate synced info to the latest version";
return;
}
WallpaperInfo local_info;
if (!pref_manager_->GetLocalWallpaperInfo(account_id, &local_info)) {
HandleWallpaperInfoSyncedIn(account_id, *synced_info);
return;
}
// TODO(b/278096886): Move this sync-out logic for `kCustomized` type
// somewhere else.
if (!synced_info->MatchesSelection(local_info) &&
synced_info->date < local_info.date &&
local_info.type == WallpaperType::kCustomized) {
// Generally, we handle setting synced_info when local_info is updated.
// But for custom images, we wait until the image is uploaded to Drive,
// which may not be available at the time of setting the local_info.
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);
}
void WallpaperControllerImpl::HandleDeprecatedSyncedWallpaperInfoAfterMigration(
const AccountId& account_id,
const std::optional<WallpaperInfo>& synced_info) {
if (!synced_info) {
LOG(WARNING) << __func__
<< " Unable to migrate synced info to the latest version";
return;
}
// Clears the deprecated pref to prevent further sync in the future.
pref_manager_->ClearDeprecatedPref(account_id);
HandleSyncedWallpaperInfoAfterMigration(account_id, *synced_info);
}
void WallpaperControllerImpl::OnWallpaperResized() {
CalculateWallpaperColors();
compositor_lock_.reset();
for (auto& observer : observers_) {
observer.OnWallpaperResized();
}
}
void WallpaperControllerImpl::OnColorCalculationComplete(
const WallpaperInfo& info,
const WallpaperCalculatedColors& wallpaper_calculated_colors) {
// Since we delete `color_calculator_` in `ShowWallpaperImage()`,
// `current_wallpaper_` should always be the same as the wallpaper for which
// color computation has been completed in production.
DCHECK(current_wallpaper_->wallpaper_info().MatchesAsset(info));
// Use |WallpaperInfo::location| as the key for storing |prominent_colors_| in
// the |kWallpaperColors| pref.
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);
// Release the color calculator after it has returned a result by calling this
// callback. There is only ever one calculator and it should always be the one
// which is fulfilling this callback.
color_calculator_.reset();
}
void WallpaperControllerImpl::OnActiveUserSessionChanged(
const AccountId& account_id) {
// It is possible to switch to another user when preview is on. In this case,
// we should close the preview and show the user's actual wallpaper.
MaybeClosePreviewWallpaper();
// We check to make sure the user's Google Photos wallpapers are still valid
// here, otherwise switching back and forth between users constantly would
// prevent us from ever checking.
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) {
// Replace the device policy wallpaper with a user wallpaper if necessary.
if (IsDevicePolicyWallpaper() && !ShouldSetDevicePolicyWallpaper())
ReloadWallpaper(/*clear_cache=*/false);
// Replace the oobe wallpaper with a user wallpaper if necessary.
if (IsOobeWallpaper()) {
ReloadWallpaper(/*clear_cache=*/false);
}
CalculateWallpaperColors();
is_session_active_ = state == session_manager::SessionState::ACTIVE;
// The wallpaper may be dimmed/blurred based on session state. The color of
// the dimming overlay depends on the prominent color cached from a previous
// calculation, or a default color if cache is not available. It should never
// depend on any in-flight color calculation.
if (wallpaper_mode_ == WALLPAPER_IMAGE &&
(state == session_manager::SessionState::ACTIVE ||
state == session_manager::SessionState::LOCKED ||
state == session_manager::SessionState::LOGIN_SECONDARY)) {
UpdateWallpaperForAllRootWindows(/*lock_state_changed=*/true);
} else {
// Just update container.
ReparentWallpaper();
}
}
void WallpaperControllerImpl::OnDisplayTabletStateChanged(
display::TabletState state) {
if (display::IsTabletStateChanging(state)) {
// Do nothing when the tablet state is still in the process of transition.
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() {
// Due to visual glitches when overview mode is activated whilst wallpaper
// preview is active (http://crbug.com/895265), cancel wallpaper preview and
// close its front-end before toggling overview mode.
MaybeClosePreviewWallpaper();
}
void WallpaperControllerImpl::OnOverviewModeStarting() {
// Only in tablet mode, we need to call `RepaintWallpaper` to update the
// wallpaper shield on overview mode changes, since in clamshell mode, we
// don't apply the wallpaper shield no matter it's in overview mode or not.
// However, in tablet mode, we need to apply the wallpaper shield when it's
// not in the overview mode.
if (display::Screen::GetScreen()->InTabletMode()) {
RepaintWallpaper();
}
}
void WallpaperControllerImpl::OnOverviewModeEnded() {
// Refer to the comment in `OnOverviewModeStarting`.
if (display::Screen::GetScreen()->InTabletMode()) {
RepaintWallpaper();
}
}
void WallpaperControllerImpl::CompositorLockTimedOut() {
compositor_lock_.reset();
}
void WallpaperControllerImpl::OnActiveUserPrefServiceChanged(
PrefService* pref_service) {
AccountId account_id = GetActiveAccountId();
// Tests may not initialize global wallpaper dirs before logging in a user.
if (sea_pen_wallpaper_manager_.ShouldMigrate(account_id) &&
!GlobalChromeOSSeaPenWallpaperDir().empty()) {
sea_pen_wallpaper_manager_.Migrate(
account_id, GetUserSeaPenWallpaperDir(account_id),
base::BindOnce(&WallpaperControllerImpl::OnSeaPenFilesMigrated,
weak_factory_.GetWeakPtr(), account_id));
}
WallpaperInfo local_info;
if (pref_manager_->GetLocalWallpaperInfo(account_id, &local_info) &&
wallpaper_info_migrator_.ShouldMigrate(local_info)) {
wallpaper_info_migrator_.Migrate(
account_id, local_info,
base::BindOnce(&WallpaperControllerImpl::SaveMigratedWallpaperInfo,
weak_factory_.GetWeakPtr()));
} else {
// If no migration is needed, proceed as before
HandleWallpaperInfoAfterMigration(account_id);
}
}
void WallpaperControllerImpl::ShowDefaultWallpaperForTesting() {
SetDefaultWallpaperImpl(user_manager::UserType::kRegular,
/*show_wallpaper=*/true, base::DoNothing());
}
void WallpaperControllerImpl::CreateEmptyWallpaperForTesting() {
ResetCalculatedColors();
current_wallpaper_.reset();
wallpaper_mode_ = WALLPAPER_IMAGE;
UpdateWallpaperForAllRootWindows(/*lock_state_changed=*/false);
// Simulate default color sampling behavior.
SetCalculatedColors(WallpaperCalculatedColors(
/*k_means=*/SK_ColorWHITE,
/*celebi=*/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, /*new_root=*/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;
// Remove small user wallpapers.
base::FilePath wallpaper_path = GetCustomWallpaperDir(kSmallWallpaperSubDir);
files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
// Remove large user wallpapers.
wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
// Remove original user wallpapers.
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) {
// There is no visible wallpaper in kiosk mode.
if (IsInKioskMode()) {
std::move(callback).Run(/*success=*/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);
// We need to decode the image if there's no cache, or if the file path
// doesn't match the cached value (i.e. the cache is outdated). Otherwise,
// directly run the callback with the cached image.
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;
// Compare layouts only if necessary.
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 = {/*in_location=*/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;
}
// Report that setting the wallpaper failed.
std::move(callback).Run(/*success=*/false);
// Log setting wallpaper failure due to fetching request failure.
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;
}
// Invalidate weak ptrs to cancel prior requests to set wallpaper.
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
online_wallpaper_manager_.GetOnlineWallpaper(
GlobalChromeOSWallpapersDir(), params->account_id, *new_info,
base::BindOnce(&WallpaperControllerImpl::OnOnlineWallpaperDecoded,
set_wallpaper_weak_factory_.GetWeakPtr(),
params->account_id, params->preview_mode, *new_info,
/*callback=*/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(/*success=*/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.";
// Keep the current wallpaper info date since the wallpaper doesn't change
// and only one of its variant gets repainted (ex: dark/light or time of day
// wallpapers).
wallpaper_info.date = current_wallpaper_->wallpaper_info().date;
}
if (preview_mode) {
DCHECK(is_active_user);
std::move(callback).Run(/*success=*/true);
confirm_preview_wallpaper_callback_ = base::BindOnce(
&WallpaperControllerImpl::SetWallpaperImpl, base::Unretained(this),
account_id, wallpaper_info, image, /*show_wallpaper=*/false);
reload_preview_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
base::Unretained(this), image, wallpaper_info,
/*preview_mode=*/true, /*is_override=*/false);
// Show the preview wallpaper.
reload_preview_wallpaper_callback_.Run();
} else {
std::move(callback).Run(/*success=*/true);
SetWallpaperImpl(account_id, wallpaper_info, image,
/*show_wallpaper=*/is_active_user);
}
}
void WallpaperControllerImpl::ShowOobeWallpaper() {
base::FilePath file_path;
if (features::IsBootAnimationEnabled()) {
file_path = base::FilePath(
FILE_PATH_LITERAL("/usr/share/chromeos-assets/animated_splash_screen/"
"oobe_wallpaper.jpg"));
} 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,
/*preview_mode=*/false, /*is_override=*/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) {
// It should be impossible for us to get back a photo successfully from
// a request that failed.
DCHECK(success || !photo);
// If the request failed, there's nothing to do here, since we can't update
// the wallpaper but also don't want to delete the cache.
if (!success) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kOnceGooglePhotos, SetWallpaperResult::kRequestFailure);
std::move(callback).Run(false);
return;
}
if (photo.is_null()) {
// The photo doesn't exist, or has been deleted. If this photo is the
// wallpaper for `params.account_id`, we need to reset to the default.
WallpaperInfo wallpaper_info;
if (GetUserWallpaperInfo(params.account_id, &wallpaper_info) &&
wallpaper_info.location == params.id) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DeleteGooglePhotosCache, params.account_id));
wallpaper_cache_map_.erase(params.account_id);
SetDefaultWallpaper(params.account_id,
/*show_wallpaper=*/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) {
// It should be impossible for us to get back a photo successfully from
// a request that failed.
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);
// If the request succeeded, but no photos came back, then the album is
// empty or deleted. Reset to default as a fallback.
SetDefaultWallpaper(params.account_id,
/*show_wallpaper=*/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;
}
// Image returned successfully. We can reliably assume success from here, and
// we need to call the callback before `ShowWallpaperImage()` to ensure proper
// propagation of `CurrentWallpaper` to the WebUI.
std::move(callback).Run(/*success=*/true);
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDailyGooglePhotos, SetWallpaperResult::kSuccess);
WallpaperInfo wallpaper_info(
{account_id, album_id, /*daily_refresh_enabled=*/true,
ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
/*preview_mode=*/false, /*dedup_key=*/std::nullopt});
wallpaper_info.location = photo_id;
wallpaper_info.dedup_key = dedup_key;
SetWallpaperImpl(account_id, wallpaper_info, image, /*show_wallpaper=*/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;
}
// Image returned successfully. We can reliably assume success from here, and
// we need to call the callback before `ShowWallpaperImage` to ensure proper
// propagation of `CurrentWallpaper` to the WebUI.
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,
/*show_wallpaper=*/false);
reload_preview_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
base::Unretained(this), image, wallpaper_info,
/*preview_mode=*/true, /*is_override=*/false);
// Show the preview wallpaper.
reload_preview_wallpaper_callback_.Run();
} else {
SetWallpaperImpl(params.account_id, wallpaper_info, image,
/*show_wallpaper=*/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, /*preview_mode=*/false,
/*is_override=*/false);
}
// Add current Google Photos wallpaper to in-memory cache.
wallpaper_cache_map_[account_id] =
CustomWallpaperElement(base::FilePath(), image);
}
void WallpaperControllerImpl::SetWallpaperFromInfo(const AccountId& account_id,
const WallpaperInfo& info) {
if (info.type == WallpaperType::kDefault) {
// Only used by WallpaperControllerTestApi.
LOG(WARNING) << "Setting a default wallpaper from info for user: "
<< account_id.Serialize()
<< " .This should only happen in test.";
SetDefaultWallpaperImpl(GetUserType(account_id), /*show_wallpaper=*/true,
base::DoNothing());
return;
}
DCHECK(!info.location.empty()) << " location should not be empty";
if (IsOnlineWallpaper(info.type)) {
auto wallpaper_path = GetOnlineWallpaperFilePath(
GlobalChromeOSWallpapersDir(), GURL(info.location),
GetAppropriateResolution());
// If the wallpaper exists and it already contains the correct image we
// can return immediately.
if (current_wallpaper_ &&
current_wallpaper_->wallpaper_info().MatchesAsset(info)) {
return;
}
// The online wallpaper must be available in the file path at this time and
// can be loaded from the path.
wallpaper_file_manager_->LoadWallpaper(
info.type, GlobalChromeOSWallpapersDir(), info.location,
base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id, wallpaper_path,
info, /*show_wallpaper=*/true));
return;
}
if (info.type == WallpaperType::kOnceGooglePhotos ||
info.type == WallpaperType::kDailyGooglePhotos) {
auto path =
GetUserGooglePhotosWallpaperDir(account_id).Append(info.location);
// The Google Photos wallpaper must be available in the file path at this
// time and can be loaded from the path.
wallpaper_file_manager_->LoadWallpaper(
info.type, GetUserGooglePhotosWallpaperDir(account_id), info.location,
base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
weak_factory_.GetWeakPtr(), account_id, path, info,
/*show_wallpaper=*/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, /*show_wallpaper=*/true));
return;
}
LOG(ERROR) << "Wallpaper reverts to default unexpected.";
wallpaper_cache_map_.erase(account_id);
SetDefaultWallpaperImpl(GetUserType(account_id), /*show_wallpaper=*/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);
// Create a solid color wallpaper if the default wallpaper decoding fails.
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;
}
// Setting default wallpaper always succeeds even if the intended image failed
// decoding. Run the callback before doing the final step of showing the
// wallpaper to be consistent with other wallpaper controller methods.
std::move(callback).Run(/*success=*/true);
if (show_wallpaper) {
WallpaperInfo info(cached_default_wallpaper_.file_path.value(), layout,
WallpaperType::kDefault, base::Time::Now());
ShowWallpaperImage(cached_default_wallpaper_.image, info,
/*preview_mode=*/false, /*is_override=*/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());
// Demo mode users are eligible for SeaPen but should not save the wallpaper
// image. Set a fake file path to use for the in memory wallpaper cache.
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,
/*preview_mode=*/false, std::move(callback),
cache_file_path);
return;
}
// Save a copy of the currently selected SeaPen wallpaper in the global
// wallpaper directory so that it is available on lock screen.
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, /*show_wallpaper=*/false);
reload_preview_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
base::Unretained(this), image_skia, wallpaper_info,
/*preview_mode=*/true, /*is_override=*/false);
// Show the preview wallpaper.
reload_preview_wallpaper_callback_.Run();
} else {
SetWallpaperImpl(account_id, wallpaper_info, image_skia,
/*show_wallpaper=*/IsActiveUser(account_id));
}
}
void WallpaperControllerImpl::OnSeaPenFilesMigrated(const AccountId& account_id,
const bool success) {
if (!success) {
LOG(WARNING) << "Failed to migrate SeaPen files";
return;
}
WallpaperInfo wallpaper_info;
if (!GetUserWallpaperInfo(account_id, &wallpaper_info)) {
LOG(WARNING) << "Failed to get user wallpaper info post SeaPen migration";
return;
}
if (wallpaper_info.type != WallpaperType::kSeaPen) {
DVLOG(0) << "Current wallpaper is not SeaPen, migration complete";
return;
}
std::optional<uint32_t> sea_pen_image_id =
GetIdFromFileName(base::FilePath(wallpaper_info.location));
if (!sea_pen_image_id.has_value()) {
LOG(WARNING) << "Invalid SeaPen info.location";
SetDefaultWallpaper(account_id, /*show_wallpaper=*/IsActiveUser(account_id),
base::DoNothing());
return;
}
SetSeaPenWallpaper(account_id, sea_pen_image_id.value(),
/*preview_mode=*/false, base::DoNothing());
}
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 the image of the new wallpaper is empty, the current wallpaper is still
// kept instead of reverting to the default.
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();
// User's custom wallpaper path is determined by relative path and the
// appropriate wallpaper resolution.
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, GlobalChromeOSCustomWallpapersDir(), file_name, layout, image,
std::move(image_saved_callback), wallpaper_files_id);
}
if (show_wallpaper) {
ShowWallpaperImage(image, info, /*preview_mode=*/false,
/*is_override=*/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) {
// Empty image indicates decode failure. Use default wallpaper in this case.
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, /*preview_mode=*/false,
/*is_override=*/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();
// Cancel any in-flight color calculation.
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) {
// Observers should be notified if this is the first call to
// `SetCalculatedColors` no matter what.
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() {
// Cancel any in-flight color calculation.
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;
}
// Color calculation is only allowed during an active session for performance
// reasons. Observers outside an active session are notified of the cache, or
// an invalid color if a previous calculation during active session failed.
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();
// Active session
if (session_state == session_manager::SessionState::ACTIVE) {
return true;
}
return false;
}
void WallpaperControllerImpl::OnOverrideWallpaperDecoded(
const WallpaperInfo& info,
const gfx::ImageSkia& image) {
// Do nothing if |RemoveOverrideWallpaper()| was called before decoding
// completes.
if (!is_override_wallpaper_) {
return;
}
if (image.isNull()) {
RemoveOverrideWallpaper();
return;
}
reload_override_wallpaper_callback_ =
base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
weak_factory_.GetWeakPtr(), image, info,
/*preview_mode=*/false, /*is_override=*/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 {
// Only allow the device wallpaper if the policy is in effect for enterprise
// managed devices.
if (device_policy_wallpaper_path_.empty())
return false;
// Only set the device wallpaper if we're at the login screen.
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) {
// It might be possible that the device policy controlled wallpaper finishes
// decoding after the user logs in. In this case do nothing.
if (!ShouldSetDevicePolicyWallpaper()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDevice, SetWallpaperResult::kPermissionDenied);
return;
}
if (image.isNull()) {
wallpaper_metrics_manager_->LogWallpaperResult(
WallpaperType::kDevice, SetWallpaperResult::kDecodingError);
// If device policy wallpaper failed decoding, fall back to the default
// wallpaper.
// TODO(crbug.com/1329567): Decide if the regular default is correct. But
// this is the current behavior for EmptyAccountId.
SetDefaultWallpaperImpl(user_manager::UserType::kRegular,
/*show_wallpaper=*/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, /*preview_mode=*/false,
/*is_override=*/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;
// We don't sync for background users because we don't want to update the
// wallpaper for background users. Instead, we call
// HandleWallpaperInfoSyncedIn again in OnActiveUserPrefServiceChanged.
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::OnTimeOfDayWallpaperSetAfterOobe(bool success) {
wallpaper_metrics_manager_->LogSettingTimeOfDayWallpaperAfterOobe(success);
}
void WallpaperControllerImpl::OnDailyRefreshWallpaperUpdated(
RefreshWallpaperCallback callback,
bool success) {
if (success) {
// Updates the check times based on when the daily wallpaper is refreshed.
// First check time is roughly 24 hours from now and the second check
// (retry) time is 25 hours (or 1 hour) from now.";
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);
// Resume observing daily refresh scheduler if necessary.
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 daily refresh is being enabled.
if (!collection_id.empty()) {
info.type = WallpaperType::kDaily;
info.collection_id = collection_id;
}
// If Daily Refresh is disabled without selecting another wallpaper, we should
// keep the current wallpaper and change to type `WallpaperType::kOnline`, so
// daily refreshes stop.
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) {
// Check if the synced info was set by another device, and if we have already
// handled it locally.
WallpaperInfo synced_info;
auto on_synced_info_migrated = base::BindOnce(
&WallpaperControllerImpl::HandleSyncedWallpaperInfoAfterMigration,
weak_factory_.GetWeakPtr(), account_id);
if (!pref_manager_->GetSyncedWallpaperInfo(account_id, &synced_info)) {
if (!features::IsVersionWallpaperInfoEnabled()) {
return;
}
// Attempts to show the user's wallpaper from the previous pref.
if (!pref_manager_->GetSyncedWallpaperInfoFromDeprecatedPref(
account_id, &synced_info)) {
return;
}
on_synced_info_migrated =
base::BindOnce(&WallpaperControllerImpl::
HandleDeprecatedSyncedWallpaperInfoAfterMigration,
weak_factory_.GetWeakPtr(), account_id);
}
if (wallpaper_info_migrator_.ShouldMigrate(synced_info)) {
wallpaper_info_migrator_.Migrate(account_id, synced_info,
std::move(on_synced_info_migrated));
} else {
// If no migration is needed, proceed as before
HandleSyncedWallpaperInfoAfterMigration(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) {
// Invalidate weak ptrs to cancel prior requests to set wallpaper.
set_wallpaper_weak_factory_.InvalidateWeakPtrs();
if (!IsDailyRefreshEnabled() && !IsDailyGooglePhotosWallpaperSelected()) {
std::move(callback).Run(false);
return;
}
// Temporarily pause observing the scheduler to avoid unnecessary
// `OnCheckpointChanged()` call after `on_done` callback is run.
daily_refresh_observation_.Reset();
auto on_done =
base::BindOnce(&WallpaperControllerImpl::OnDailyRefreshWallpaperUpdated,
weak_factory_.GetWeakPtr(), std::move(callback));
AccountId account_id = GetActiveAccountId();
WallpaperInfo info;
// |wallpaper_controller_cient_| has a slightly shorter lifecycle than
// wallpaper controller.
if (wallpaper_controller_client_ && GetUserWallpaperInfo(account_id, &info)) {
if (info.type == WallpaperType::kDailyGooglePhotos) {
SetGooglePhotosWallpaper(
GooglePhotosWallpaperParams(
account_id, info.collection_id,
/*daily_refresh_enabled=*/true, info.layout,
/*preview_mode=*/false, /*dedup_key=*/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));
// Fetch can fail if wallpaper_controller_client has been cleared or
// |info| is malformed.
if (!variant_info_fetcher_.FetchDailyWallpaper(
account_id, info, std::move(fetch_callback))) {
// Could not start fetch of wallpaper variants. Likely because the
// chrome client isn't ready. Schedule for later.
NOTREACHED() << "Failed to initiate daily wallpaper fetch";
}
}
} else {
std::move(on_done).Run(false);
}
}
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` is false, then we failed to connect to the Google Photos API
// for some reason. We're already set to try again later, since the timer was
// reset to one hour in `CheckGooglePhotosStaleness`.
if (!success)
return;
if (!photo) {
sequenced_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DeleteGooglePhotosCache, account_id));
SetDefaultWallpaper(account_id, /*show_wallpaper=*/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) {
// If the drivefs image modification time is null, watch DriveFS for the
// file being created. If the file exists but is older than synced wallpaper
// info, watch for the file being updated by the other device.
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,
/*show_wallpaper=*/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) {
// We only want to update the user's `WallpaperInfo` if this is a new
// album. Otherwise, each time the daily refresh timer expires on multiple
// devices we could trigger devices to refresh multiple times.
WallpaperInfo old_info;
if (GetUserWallpaperInfo(account_id, &old_info) &&
old_info.collection_id != info.collection_id) {
SetGooglePhotosWallpaper(
GooglePhotosWallpaperParams(
account_id, info.collection_id,
/*daily_refresh_enabled=*/true, info.layout,
/*preview_mode=*/false, /*dedup_key=*/std::nullopt),
base::DoNothing());
}
} else {
SetGooglePhotosWallpaper(GooglePhotosWallpaperParams(
account_id, info.location,
/*daily_refresh_enabled=*/false, info.layout,
/*preview_mode=*/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) {
directories_to_remove.push_back(
GetUserGooglePhotosWallpaperDir(account_id));
}
if (account_id.HasAccountIdKey() && info.type != WallpaperType::kSeaPen) {
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();
// Default OOBE flow
const bool is_default_oobe_flow =
session_state == session_manager::SessionState::OOBE;
// OOBE enterprise enrollment -> add person flow
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();
}
}
} // namespace ash