1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/wallpaper/wallpaper_controller_impl.h"
6
7 #include <memory>
8 #include <numeric>
9 #include <string>
10 #include <utility>
11
12 #include "ash/display/window_tree_host_manager.h"
13 #include "ash/public/cpp/ash_pref_names.h"
14 #include "ash/public/cpp/ash_switches.h"
15 #include "ash/public/cpp/login_constants.h"
16 #include "ash/public/cpp/shell_window_ids.h"
17 #include "ash/public/cpp/wallpaper_controller_client.h"
18 #include "ash/public/cpp/wallpaper_controller_observer.h"
19 #include "ash/root_window_controller.h"
20 #include "ash/session/session_controller_impl.h"
21 #include "ash/shell.h"
22 #include "ash/shell_delegate.h"
23 #include "ash/wallpaper/wallpaper_utils/wallpaper_color_calculator.h"
24 #include "ash/wallpaper/wallpaper_utils/wallpaper_decoder.h"
25 #include "ash/wallpaper/wallpaper_utils/wallpaper_resizer.h"
26 #include "ash/wallpaper/wallpaper_view.h"
27 #include "ash/wallpaper/wallpaper_widget_controller.h"
28 #include "ash/wallpaper/wallpaper_window_state_manager.h"
29 #include "ash/wm/overview/overview_constants.h"
30 #include "ash/wm/overview/overview_controller.h"
31 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
32 #include "base/bind.h"
33 #include "base/command_line.h"
34 #include "base/files/file_enumerator.h"
35 #include "base/files/file_util.h"
36 #include "base/logging.h"
37 #include "base/memory/ptr_util.h"
38 #include "base/memory/ref_counted_memory.h"
39 #include "base/metrics/histogram_macros.h"
40 #include "base/no_destructor.h"
41 #include "base/numerics/safe_conversions.h"
42 #include "base/path_service.h"
43 #include "base/sequenced_task_runner.h"
44 #include "base/strings/string_number_conversions.h"
45 #include "base/task/post_task.h"
46 #include "base/task/thread_pool.h"
47 #include "base/task_runner_util.h"
48 #include "base/values.h"
49 #include "chromeos/constants/chromeos_switches.h"
50 #include "components/prefs/pref_registry_simple.h"
51 #include "components/prefs/pref_service.h"
52 #include "components/prefs/scoped_user_pref_update.h"
53 #include "components/user_manager/user_manager.h"
54 #include "components/user_manager/user_type.h"
55 #include "services/data_decoder/public/cpp/decode_image.h"
56 #include "ui/display/manager/display_manager.h"
57 #include "ui/display/manager/managed_display_info.h"
58 #include "ui/display/screen.h"
59 #include "ui/gfx/codec/jpeg_codec.h"
60 #include "ui/gfx/color_analysis.h"
61 #include "ui/gfx/image/image_skia.h"
62 #include "ui/gfx/image/image_skia_operations.h"
63 #include "ui/views/widget/widget.h"
64
65 using color_utils::ColorProfile;
66 using color_utils::LumaRange;
67 using color_utils::SaturationRange;
68
69 namespace ash {
70
71 namespace {
72
73 // Names of nodes with wallpaper info in |kUserWallpaperInfo| dictionary.
74 constexpr char kNewWallpaperDateNodeName[] = "date";
75 constexpr char kNewWallpaperLayoutNodeName[] = "layout";
76 constexpr char kNewWallpaperLocationNodeName[] = "file";
77 constexpr char kNewWallpaperTypeNodeName[] = "type";
78
79 // The file name of the policy wallpaper.
80 constexpr char kPolicyWallpaperFile[] = "policy-controlled.jpeg";
81
82 // File path suffix of resized small wallpapers.
83 constexpr char kSmallWallpaperSuffix[] = "_small";
84
85 // How long to wait reloading the wallpaper after the display size has changed.
86 constexpr base::TimeDelta kWallpaperReloadDelay =
87 base::TimeDelta::FromMilliseconds(100);
88
89 // How long to wait for resizing of the the wallpaper.
90 constexpr base::TimeDelta kCompositorLockTimeout =
91 base::TimeDelta::FromMilliseconds(750);
92
93 // Duration of the lock animation performed when pressing a lock button.
94 constexpr base::TimeDelta kLockAnimationBlurAnimationDuration =
95 base::TimeDelta::FromMilliseconds(100);
96
97 // Duration of the cross fade animation when loading wallpaper.
98 constexpr base::TimeDelta kWallpaperLoadAnimationDuration =
99 base::TimeDelta::FromMilliseconds(250);
100
101 // Default quality for encoding wallpaper.
102 constexpr int kDefaultEncodingQuality = 90;
103
104 // The color of the wallpaper if no other wallpaper images are available.
105 constexpr SkColor kDefaultWallpaperColor = SK_ColorGRAY;
106
107 // The paths of wallpaper directories.
GlobalUserDataDir()108 base::FilePath& GlobalUserDataDir() {
109 static base::NoDestructor<base::FilePath> dir_user_data;
110 return *dir_user_data;
111 }
112
GlobalChromeOSWallpapersDir()113 base::FilePath& GlobalChromeOSWallpapersDir() {
114 static base::NoDestructor<base::FilePath> dir_chrome_os_wallpapers;
115 return *dir_chrome_os_wallpapers;
116 }
117
GlobalChromeOSCustomWallpapersDir()118 base::FilePath& GlobalChromeOSCustomWallpapersDir() {
119 static base::NoDestructor<base::FilePath> dir_chrome_os_custom_wallpapers;
120 return *dir_chrome_os_custom_wallpapers;
121 }
122
SetGlobalUserDataDir(const base::FilePath & path)123 void SetGlobalUserDataDir(const base::FilePath& path) {
124 base::FilePath& global_path = GlobalUserDataDir();
125 global_path = path;
126 }
127
SetGlobalChromeOSWallpapersDir(const base::FilePath & path)128 void SetGlobalChromeOSWallpapersDir(const base::FilePath& path) {
129 base::FilePath& global_path = GlobalChromeOSWallpapersDir();
130 global_path = path;
131 }
132
SetGlobalChromeOSCustomWallpapersDir(const base::FilePath & path)133 void SetGlobalChromeOSCustomWallpapersDir(const base::FilePath& path) {
134 base::FilePath& global_path = GlobalChromeOSCustomWallpapersDir();
135 global_path = path;
136 }
137
138 // Returns the appropriate wallpaper resolution for all root windows.
GetAppropriateResolution()139 WallpaperControllerImpl::WallpaperResolution GetAppropriateResolution() {
140 gfx::Size size = WallpaperControllerImpl::GetMaxDisplaySizeInNative();
141 return (size.width() > kSmallWallpaperMaxWidth ||
142 size.height() > kSmallWallpaperMaxHeight)
143 ? WallpaperControllerImpl::WALLPAPER_RESOLUTION_LARGE
144 : WallpaperControllerImpl::WALLPAPER_RESOLUTION_SMALL;
145 }
146
147 // Returns the path of the online wallpaper corresponding to |url| and
148 // |resolution|.
GetOnlineWallpaperPath(const std::string & url,WallpaperControllerImpl::WallpaperResolution resolution)149 base::FilePath GetOnlineWallpaperPath(
150 const std::string& url,
151 WallpaperControllerImpl::WallpaperResolution resolution) {
152 std::string file_name = GURL(url).ExtractFileName();
153 if (resolution == WallpaperControllerImpl::WALLPAPER_RESOLUTION_SMALL) {
154 file_name = base::FilePath(file_name)
155 .InsertBeforeExtension(kSmallWallpaperSuffix)
156 .value();
157 }
158 DCHECK(!GlobalChromeOSWallpapersDir().empty());
159 return GlobalChromeOSWallpapersDir().Append(file_name);
160 }
161
162 // Returns wallpaper subdirectory name for current resolution.
GetCustomWallpaperSubdirForCurrentResolution()163 std::string GetCustomWallpaperSubdirForCurrentResolution() {
164 WallpaperControllerImpl::WallpaperResolution resolution =
165 GetAppropriateResolution();
166 return resolution == WallpaperControllerImpl::WALLPAPER_RESOLUTION_SMALL
167 ? WallpaperControllerImpl::kSmallWallpaperSubDir
168 : WallpaperControllerImpl::kLargeWallpaperSubDir;
169 }
170
171 // Resizes |image| to a resolution which is nearest to |preferred_width| and
172 // |preferred_height| while respecting the |layout| choice. Encodes the image to
173 // JPEG and saves to |output|. Returns true on success.
ResizeAndEncodeImage(const gfx::ImageSkia & image,WallpaperLayout layout,int preferred_width,int preferred_height,scoped_refptr<base::RefCountedBytes> * output)174 bool ResizeAndEncodeImage(const gfx::ImageSkia& image,
175 WallpaperLayout layout,
176 int preferred_width,
177 int preferred_height,
178 scoped_refptr<base::RefCountedBytes>* output) {
179 int width = image.width();
180 int height = image.height();
181 int resized_width;
182 int resized_height;
183 *output = base::MakeRefCounted<base::RefCountedBytes>();
184
185 if (layout == WALLPAPER_LAYOUT_CENTER_CROPPED) {
186 // Do not resize wallpaper if it is smaller than preferred size.
187 if (width < preferred_width || height < preferred_height)
188 return false;
189
190 double horizontal_ratio = static_cast<double>(preferred_width) / width;
191 double vertical_ratio = static_cast<double>(preferred_height) / height;
192 if (vertical_ratio > horizontal_ratio) {
193 resized_width =
194 base::ClampRound(static_cast<double>(width) * vertical_ratio);
195 resized_height = preferred_height;
196 } else {
197 resized_width = preferred_width;
198 resized_height =
199 base::ClampRound(static_cast<double>(height) * horizontal_ratio);
200 }
201 } else if (layout == WALLPAPER_LAYOUT_STRETCH) {
202 resized_width = preferred_width;
203 resized_height = preferred_height;
204 } else {
205 resized_width = width;
206 resized_height = height;
207 }
208
209 gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage(
210 image, skia::ImageOperations::RESIZE_LANCZOS3,
211 gfx::Size(resized_width, resized_height));
212
213 SkBitmap bitmap = *(resized_image.bitmap());
214 gfx::JPEGCodec::Encode(bitmap, kDefaultEncodingQuality, &(*output)->data());
215 return true;
216 }
217
218 // Resizes |image| to a resolution which is nearest to |preferred_width| and
219 // |preferred_height| while respecting the |layout| choice and saves the
220 // resized wallpaper to |path|. Returns true on success.
ResizeAndSaveWallpaper(const gfx::ImageSkia & image,const base::FilePath & path,WallpaperLayout layout,int preferred_width,int preferred_height)221 bool ResizeAndSaveWallpaper(const gfx::ImageSkia& image,
222 const base::FilePath& path,
223 WallpaperLayout layout,
224 int preferred_width,
225 int preferred_height) {
226 if (layout == WALLPAPER_LAYOUT_CENTER) {
227 if (base::PathExists(path))
228 base::DeleteFile(path);
229 return false;
230 }
231 scoped_refptr<base::RefCountedBytes> data;
232 if (!ResizeAndEncodeImage(image, layout, preferred_width, preferred_height,
233 &data)) {
234 return false;
235 }
236
237 // Saves |data| to |path| in local file system.
238 size_t written_bytes =
239 base::WriteFile(path, data->front_as<const char>(), data->size());
240 return written_bytes == data->size();
241 }
242
243 // Creates a 1x1 solid color image.
CreateSolidColorWallpaper(SkColor color)244 gfx::ImageSkia CreateSolidColorWallpaper(SkColor color) {
245 SkBitmap bitmap;
246 bitmap.allocN32Pixels(1, 1);
247 bitmap.eraseColor(color);
248 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
249 }
250
251 // Gets the color profiles for extracting wallpaper prominent colors.
GetProminentColorProfiles()252 std::vector<ColorProfile> GetProminentColorProfiles() {
253 return {ColorProfile(LumaRange::DARK, SaturationRange::VIBRANT),
254 ColorProfile(LumaRange::NORMAL, SaturationRange::VIBRANT),
255 ColorProfile(LumaRange::LIGHT, SaturationRange::VIBRANT),
256 ColorProfile(LumaRange::DARK, SaturationRange::MUTED),
257 ColorProfile(LumaRange::NORMAL, SaturationRange::MUTED),
258 ColorProfile(LumaRange::LIGHT, SaturationRange::MUTED)};
259 }
260
261 // Gets the corresponding color profile type based on the given
262 // |color_profile|.
GetColorProfileType(ColorProfile color_profile)263 ColorProfileType GetColorProfileType(ColorProfile color_profile) {
264 bool vibrant = color_profile.saturation == SaturationRange::VIBRANT;
265 switch (color_profile.luma) {
266 case LumaRange::ANY:
267 // There should be no color profiles with the ANY luma range.
268 NOTREACHED();
269 break;
270 case LumaRange::DARK:
271 return vibrant ? ColorProfileType::DARK_VIBRANT
272 : ColorProfileType::DARK_MUTED;
273 case LumaRange::NORMAL:
274 return vibrant ? ColorProfileType::NORMAL_VIBRANT
275 : ColorProfileType::NORMAL_MUTED;
276 case LumaRange::LIGHT:
277 return vibrant ? ColorProfileType::LIGHT_VIBRANT
278 : ColorProfileType::LIGHT_MUTED;
279 }
280 NOTREACHED();
281 return ColorProfileType::DARK_MUTED;
282 }
283
284 // If |read_is_successful| is true, start decoding the image, which will run
285 // |callback| upon completion; if it's false, run |callback| directly with an
286 // empty image.
OnWallpaperDataRead(LoadedCallback callback,std::unique_ptr<std::string> data,bool read_is_successful)287 void OnWallpaperDataRead(LoadedCallback callback,
288 std::unique_ptr<std::string> data,
289 bool read_is_successful) {
290 if (!read_is_successful) {
291 base::ThreadTaskRunnerHandle::Get()->PostTask(
292 FROM_HERE, base::BindOnce(std::move(callback), gfx::ImageSkia()));
293 return;
294 }
295 // This image was once encoded to JPEG by |ResizeAndEncodeImage|.
296 DecodeWallpaper(*data, data_decoder::mojom::ImageCodec::DEFAULT,
297 std::move(callback));
298 }
299
300 // Deletes a list of wallpaper files in |file_list|.
DeleteWallpaperInList(std::vector<base::FilePath> file_list)301 void DeleteWallpaperInList(std::vector<base::FilePath> file_list) {
302 for (const base::FilePath& path : file_list) {
303 if (!base::DeletePathRecursively(path))
304 LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
305 }
306 }
307
308 // Creates all new custom wallpaper directories for |wallpaper_files_id| if they
309 // don't exist.
EnsureCustomWallpaperDirectories(const std::string & wallpaper_files_id)310 void EnsureCustomWallpaperDirectories(const std::string& wallpaper_files_id) {
311 base::FilePath dir = WallpaperControllerImpl::GetCustomWallpaperDir(
312 WallpaperControllerImpl::kSmallWallpaperSubDir)
313 .Append(wallpaper_files_id);
314 if (!base::PathExists(dir))
315 base::CreateDirectory(dir);
316
317 dir = WallpaperControllerImpl::GetCustomWallpaperDir(
318 WallpaperControllerImpl::kLargeWallpaperSubDir)
319 .Append(wallpaper_files_id);
320
321 if (!base::PathExists(dir))
322 base::CreateDirectory(dir);
323
324 dir = WallpaperControllerImpl::GetCustomWallpaperDir(
325 WallpaperControllerImpl::kOriginalWallpaperSubDir)
326 .Append(wallpaper_files_id);
327 if (!base::PathExists(dir))
328 base::CreateDirectory(dir);
329 }
330
331 // Saves original custom wallpaper to |path| (absolute path) on filesystem
332 // and starts resizing operation of the custom wallpaper if necessary.
SaveCustomWallpaper(const std::string & wallpaper_files_id,const base::FilePath & original_path,WallpaperLayout layout,gfx::ImageSkia image)333 void SaveCustomWallpaper(const std::string& wallpaper_files_id,
334 const base::FilePath& original_path,
335 WallpaperLayout layout,
336 gfx::ImageSkia image) {
337 base::DeletePathRecursively(
338 WallpaperControllerImpl::GetCustomWallpaperDir(
339 WallpaperControllerImpl::kOriginalWallpaperSubDir)
340 .Append(wallpaper_files_id));
341 base::DeletePathRecursively(
342 WallpaperControllerImpl::GetCustomWallpaperDir(
343 WallpaperControllerImpl::kSmallWallpaperSubDir)
344 .Append(wallpaper_files_id));
345 base::DeletePathRecursively(
346 WallpaperControllerImpl::GetCustomWallpaperDir(
347 WallpaperControllerImpl::kLargeWallpaperSubDir)
348 .Append(wallpaper_files_id));
349 EnsureCustomWallpaperDirectories(wallpaper_files_id);
350 const std::string file_name = original_path.BaseName().value();
351 const base::FilePath small_wallpaper_path =
352 WallpaperControllerImpl::GetCustomWallpaperPath(
353 WallpaperControllerImpl::kSmallWallpaperSubDir, wallpaper_files_id,
354 file_name);
355 const base::FilePath large_wallpaper_path =
356 WallpaperControllerImpl::GetCustomWallpaperPath(
357 WallpaperControllerImpl::kLargeWallpaperSubDir, wallpaper_files_id,
358 file_name);
359
360 // Re-encode orginal file to jpeg format and saves the result in case that
361 // resized wallpaper is not generated (i.e. chrome shutdown before resized
362 // wallpaper is saved).
363 ResizeAndSaveWallpaper(image, original_path, WALLPAPER_LAYOUT_STRETCH,
364 image.width(), image.height());
365 ResizeAndSaveWallpaper(image, small_wallpaper_path, layout,
366 kSmallWallpaperMaxWidth, kSmallWallpaperMaxHeight);
367 ResizeAndSaveWallpaper(image, large_wallpaper_path, layout,
368 kLargeWallpaperMaxWidth, kLargeWallpaperMaxHeight);
369 }
370
371 // Checks if kiosk app is running. Note: it returns false either when there's
372 // no active user (e.g. at login screen), or the active user is not kiosk.
IsInKioskMode()373 bool IsInKioskMode() {
374 base::Optional<user_manager::UserType> active_user_type =
375 Shell::Get()->session_controller()->GetUserType();
376 // |active_user_type| is empty when there's no active user.
377 return active_user_type &&
378 *active_user_type == user_manager::USER_TYPE_KIOSK_APP;
379 }
380
381 // Returns the currently active user session (at index 0).
GetActiveUserSession()382 const UserSession* GetActiveUserSession() {
383 return Shell::Get()->session_controller()->GetUserSession(/*user index=*/0);
384 }
385
386 // Checks if |account_id| is the current active user.
IsActiveUser(const AccountId & account_id)387 bool IsActiveUser(const AccountId& account_id) {
388 const UserSession* const session = GetActiveUserSession();
389 return session && session->user_info.account_id == account_id;
390 }
391
392 // Returns the file path of the wallpaper corresponding to |url| if it exists in
393 // local file system, otherwise returns an empty file path.
GetExistingOnlineWallpaperPath(const std::string & url)394 base::FilePath GetExistingOnlineWallpaperPath(const std::string& url) {
395 WallpaperControllerImpl::WallpaperResolution resolution =
396 GetAppropriateResolution();
397 base::FilePath wallpaper_path = GetOnlineWallpaperPath(url, resolution);
398 if (base::PathExists(wallpaper_path))
399 return wallpaper_path;
400
401 // Falls back to the large wallpaper if the small one doesn't exist.
402 if (resolution == WallpaperControllerImpl::WALLPAPER_RESOLUTION_SMALL) {
403 wallpaper_path = GetOnlineWallpaperPath(
404 url, WallpaperControllerImpl::WALLPAPER_RESOLUTION_LARGE);
405 if (base::PathExists(wallpaper_path))
406 return wallpaper_path;
407 }
408 return base::FilePath();
409 }
410
411 // Saves the online wallpaper with both large and small sizes to local file
412 // system.
SaveOnlineWallpaper(const std::string & url,WallpaperLayout layout,gfx::ImageSkia image)413 void SaveOnlineWallpaper(const std::string& url,
414 WallpaperLayout layout,
415 gfx::ImageSkia image) {
416 DCHECK(!GlobalChromeOSWallpapersDir().empty());
417 if (!base::DirectoryExists(GlobalChromeOSWallpapersDir()) &&
418 !base::CreateDirectory(GlobalChromeOSWallpapersDir())) {
419 return;
420 }
421 ResizeAndSaveWallpaper(
422 image,
423 GetOnlineWallpaperPath(
424 url, WallpaperControllerImpl::WALLPAPER_RESOLUTION_LARGE),
425 layout, image.width(), image.height());
426 ResizeAndSaveWallpaper(
427 image,
428 GetOnlineWallpaperPath(
429 url, WallpaperControllerImpl::WALLPAPER_RESOLUTION_SMALL),
430 WALLPAPER_LAYOUT_CENTER_CROPPED, kSmallWallpaperMaxWidth,
431 kSmallWallpaperMaxHeight);
432 }
433
434 // Implementation of |WallpaperControllerImpl::GetOfflineWallpaper|.
GetOfflineWallpaperListImpl()435 std::vector<std::string> GetOfflineWallpaperListImpl() {
436 DCHECK(!GlobalChromeOSWallpapersDir().empty());
437 std::vector<std::string> url_list;
438 if (base::DirectoryExists(GlobalChromeOSWallpapersDir())) {
439 base::FileEnumerator files(GlobalChromeOSWallpapersDir(),
440 /*recursive=*/false,
441 base::FileEnumerator::FILES);
442 for (base::FilePath current = files.Next(); !current.empty();
443 current = files.Next()) {
444 // Do not add file name of small resolution wallpaper to the list.
445 if (!base::EndsWith(current.BaseName().RemoveExtension().value(),
446 kSmallWallpaperSuffix,
447 base::CompareCase::SENSITIVE)) {
448 url_list.push_back(current.BaseName().value());
449 }
450 }
451 }
452 return url_list;
453 }
454
455 // Returns true if the user's wallpaper is to be treated as ephemeral.
IsEphemeralUser(const AccountId & id)456 bool IsEphemeralUser(const AccountId& id) {
457 if (user_manager::UserManager::IsInitialized()) {
458 return user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral(
459 id);
460 }
461 NOTIMPLEMENTED();
462 return false;
463 }
464
465 // Returns the type of the user with the specified |id| or USER_TYPE_REGULAR.
GetUserType(const AccountId & id)466 user_manager::UserType GetUserType(const AccountId& id) {
467 if (user_manager::UserManager::IsInitialized()) {
468 if (auto* user = user_manager::UserManager::Get()->FindUser(id))
469 return user->GetType();
470 }
471 NOTIMPLEMENTED();
472 return user_manager::USER_TYPE_REGULAR;
473 }
474
475 } // namespace
476
477 const char WallpaperControllerImpl::kSmallWallpaperSubDir[] = "small";
478 const char WallpaperControllerImpl::kLargeWallpaperSubDir[] = "large";
479 const char WallpaperControllerImpl::kOriginalWallpaperSubDir[] = "original";
480
WallpaperControllerImpl(PrefService * local_state)481 WallpaperControllerImpl::WallpaperControllerImpl(PrefService* local_state)
482 : color_profiles_(GetProminentColorProfiles()),
483 wallpaper_reload_delay_(kWallpaperReloadDelay),
484 sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
485 {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
486 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
487 local_state_(local_state) {
488 DCHECK(!g_instance_);
489 g_instance_ = this;
490 DCHECK(!color_profiles_.empty());
491 prominent_colors_ =
492 std::vector<SkColor>(color_profiles_.size(), kInvalidWallpaperColor);
493 Shell::Get()->window_tree_host_manager()->AddObserver(this);
494 Shell::Get()->AddShellObserver(this);
495 }
496
~WallpaperControllerImpl()497 WallpaperControllerImpl::~WallpaperControllerImpl() {
498 if (current_wallpaper_)
499 current_wallpaper_->RemoveObserver(this);
500 if (color_calculator_)
501 color_calculator_->RemoveObserver(this);
502 Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
503 Shell::Get()->RemoveShellObserver(this);
504 weak_factory_.InvalidateWeakPtrs();
505 DCHECK_EQ(g_instance_, this);
506 g_instance_ = nullptr;
507 }
508
509 // static
RegisterLocalStatePrefs(PrefRegistrySimple * registry)510 void WallpaperControllerImpl::RegisterLocalStatePrefs(
511 PrefRegistrySimple* registry) {
512 registry->RegisterDictionaryPref(prefs::kUserWallpaperInfo);
513 registry->RegisterDictionaryPref(prefs::kWallpaperColors);
514 }
515
516 // static
GetMaxDisplaySizeInNative()517 gfx::Size WallpaperControllerImpl::GetMaxDisplaySizeInNative() {
518 // Return an empty size for test environments where the screen is null.
519 if (!display::Screen::GetScreen())
520 return gfx::Size();
521
522 gfx::Size max;
523 for (const auto& display : display::Screen::GetScreen()->GetAllDisplays())
524 max.SetToMax(display.GetSizeInPixel());
525
526 return max;
527 }
528
529 // static
GetCustomWallpaperPath(const std::string & sub_dir,const std::string & wallpaper_files_id,const std::string & file_name)530 base::FilePath WallpaperControllerImpl::GetCustomWallpaperPath(
531 const std::string& sub_dir,
532 const std::string& wallpaper_files_id,
533 const std::string& file_name) {
534 base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
535 return custom_wallpaper_path.Append(wallpaper_files_id).Append(file_name);
536 }
537
538 // static
GetCustomWallpaperDir(const std::string & sub_dir)539 base::FilePath WallpaperControllerImpl::GetCustomWallpaperDir(
540 const std::string& sub_dir) {
541 DCHECK(!GlobalChromeOSCustomWallpapersDir().empty());
542 return GlobalChromeOSCustomWallpapersDir().Append(sub_dir);
543 }
544
545 // static
SetWallpaperFromPath(const AccountId & account_id,const WallpaperInfo & info,const base::FilePath & wallpaper_path,bool show_wallpaper,const scoped_refptr<base::SingleThreadTaskRunner> & reply_task_runner,base::WeakPtr<WallpaperControllerImpl> weak_ptr)546 void WallpaperControllerImpl::SetWallpaperFromPath(
547 const AccountId& account_id,
548 const WallpaperInfo& info,
549 const base::FilePath& wallpaper_path,
550 bool show_wallpaper,
551 const scoped_refptr<base::SingleThreadTaskRunner>& reply_task_runner,
552 base::WeakPtr<WallpaperControllerImpl> weak_ptr) {
553 base::FilePath valid_path = wallpaper_path;
554 if (!base::PathExists(valid_path)) {
555 // Falls back to the original file if the file with correct resolution does
556 // not exist. This may happen when the original custom wallpaper is small or
557 // browser shutdown before resized wallpaper saved.
558 valid_path =
559 GetCustomWallpaperDir(kOriginalWallpaperSubDir).Append(info.location);
560 }
561
562 if (!base::PathExists(valid_path)) {
563 LOG(ERROR) << "The path " << valid_path.value()
564 << " doesn't exist. Falls back to default wallpaper.";
565 reply_task_runner->PostTask(
566 FROM_HERE,
567 base::BindOnce(&WallpaperControllerImpl::SetDefaultWallpaperImpl,
568 weak_ptr, account_id, show_wallpaper));
569 } else {
570 reply_task_runner->PostTask(
571 FROM_HERE,
572 base::BindOnce(&WallpaperControllerImpl::StartDecodeFromPath, weak_ptr,
573 account_id, valid_path, info, show_wallpaper));
574 }
575 }
576
GetProminentColor(ColorProfile color_profile) const577 SkColor WallpaperControllerImpl::GetProminentColor(
578 ColorProfile color_profile) const {
579 ColorProfileType type = GetColorProfileType(color_profile);
580 return prominent_colors_[static_cast<int>(type)];
581 }
582
GetWallpaper() const583 gfx::ImageSkia WallpaperControllerImpl::GetWallpaper() const {
584 return current_wallpaper_ ? current_wallpaper_->image() : gfx::ImageSkia();
585 }
586
GetWallpaperLayout() const587 WallpaperLayout WallpaperControllerImpl::GetWallpaperLayout() const {
588 return current_wallpaper_ ? current_wallpaper_->wallpaper_info().layout
589 : NUM_WALLPAPER_LAYOUT;
590 }
591
GetWallpaperType() const592 WallpaperType WallpaperControllerImpl::GetWallpaperType() const {
593 return current_wallpaper_ ? current_wallpaper_->wallpaper_info().type
594 : WALLPAPER_TYPE_COUNT;
595 }
596
ShouldShowInitialAnimation()597 bool WallpaperControllerImpl::ShouldShowInitialAnimation() {
598 // The slower initial animation is only applicable if:
599 // 1) It's the first run after system boot, not after user sign-out.
600 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
601 chromeos::switches::kFirstExecAfterBoot)) {
602 return false;
603 }
604 // 2) It's at the login screen.
605 if (Shell::Get()->session_controller()->IsActiveUserSessionStarted() ||
606 !base::CommandLine::ForCurrentProcess()->HasSwitch(
607 chromeos::switches::kLoginManager)) {
608 return false;
609 }
610 // 3) It's the first wallpaper being shown, not for the switching between
611 // multiple user pods.
612 if (!is_first_wallpaper_)
613 return false;
614
615 return true;
616 }
617
CanOpenWallpaperPicker()618 bool WallpaperControllerImpl::CanOpenWallpaperPicker() {
619 return ShouldShowWallpaperSetting() &&
620 !IsActiveUserWallpaperControlledByPolicy();
621 }
622
HasShownAnyWallpaper() const623 bool WallpaperControllerImpl::HasShownAnyWallpaper() const {
624 return !!current_wallpaper_;
625 }
626
MaybeClosePreviewWallpaper()627 void WallpaperControllerImpl::MaybeClosePreviewWallpaper() {
628 if (!confirm_preview_wallpaper_callback_) {
629 DCHECK(!reload_preview_wallpaper_callback_);
630 return;
631 }
632 wallpaper_controller_client_->MaybeClosePreviewWallpaper();
633 CancelPreviewWallpaper();
634 }
635
ShowWallpaperImage(const gfx::ImageSkia & image,WallpaperInfo info,bool preview_mode,bool always_on_top)636 void WallpaperControllerImpl::ShowWallpaperImage(const gfx::ImageSkia& image,
637 WallpaperInfo info,
638 bool preview_mode,
639 bool always_on_top) {
640 // Prevent showing other wallpapers if there is an always-on-top wallpaper.
641 if (is_always_on_top_wallpaper_ && !always_on_top)
642 return;
643
644 // Ignore show wallpaper requests during preview mode. This could happen if a
645 // custom wallpaper previously set on another device is being synced.
646 if (confirm_preview_wallpaper_callback_ && !preview_mode)
647 return;
648
649 if (preview_mode) {
650 for (auto& observer : observers_)
651 observer.OnWallpaperPreviewStarted();
652 }
653
654 // 1x1 wallpaper should be stretched to fill the entire screen.
655 // (WALLPAPER_LAYOUT_TILE also serves this purpose.)
656 if (image.width() == 1 && image.height() == 1)
657 info.layout = WALLPAPER_LAYOUT_STRETCH;
658
659 if (info.type == WallpaperType::ONE_SHOT)
660 info.one_shot_wallpaper = image.DeepCopy();
661
662 VLOG(1) << "SetWallpaper: image_id=" << WallpaperResizer::GetImageId(image)
663 << " layout=" << info.layout;
664
665 if (WallpaperIsAlreadyLoaded(image, /*compare_layouts=*/true, info.layout)) {
666 VLOG(1) << "Wallpaper is already loaded";
667 return;
668 }
669
670 UMA_HISTOGRAM_ENUMERATION("Ash.Wallpaper.Type", info.type,
671 WALLPAPER_TYPE_COUNT);
672
673 // Cancel any in-flight color calculation because we have a new wallpaper.
674 if (color_calculator_) {
675 color_calculator_->RemoveObserver(this);
676 color_calculator_.reset();
677 }
678
679 is_first_wallpaper_ = !current_wallpaper_;
680 current_wallpaper_ = std::make_unique<WallpaperResizer>(
681 image, GetMaxDisplaySizeInNative(), info, sequenced_task_runner_);
682 current_wallpaper_->AddObserver(this);
683 current_wallpaper_->StartResize();
684
685 if (is_first_wallpaper_) {
686 for (auto& observer : observers_)
687 observer.OnFirstWallpaperShown();
688 }
689
690 for (auto& observer : observers_)
691 observer.OnWallpaperChanging();
692
693 wallpaper_mode_ = WALLPAPER_IMAGE;
694 UpdateWallpaperForAllRootWindows(
695 Shell::Get()->session_controller()->IsUserSessionBlocked());
696 ++wallpaper_count_for_testing_;
697
698 for (auto& observer : observers_)
699 observer.OnWallpaperChanged();
700 }
701
IsPolicyControlled(const AccountId & account_id) const702 bool WallpaperControllerImpl::IsPolicyControlled(
703 const AccountId& account_id) const {
704 WallpaperInfo info;
705 return GetUserWallpaperInfo(account_id, &info) && info.type == POLICY;
706 }
707
UpdateWallpaperBlurForLockState(bool blur)708 void WallpaperControllerImpl::UpdateWallpaperBlurForLockState(bool blur) {
709 if (!IsBlurAllowedForLockState())
710 return;
711
712 bool changed = is_wallpaper_blurred_for_lock_state_ != blur;
713 // is_wallpaper_blurrred_for_lock_state_ may already be updated in
714 // InstallDesktopController. Always try to update, then invoke observer
715 // if something changed.
716 for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
717 changed |=
718 root_window_controller->wallpaper_widget_controller()->SetWallpaperBlur(
719 blur ? wallpaper_constants::kLockLoginBlur
720 : wallpaper_constants::kClear,
721 kLockAnimationBlurAnimationDuration);
722 }
723
724 is_wallpaper_blurred_for_lock_state_ = blur;
725 if (changed) {
726 for (auto& observer : observers_)
727 observer.OnWallpaperBlurChanged();
728 }
729 }
730
RestoreWallpaperBlurForLockState(float blur)731 void WallpaperControllerImpl::RestoreWallpaperBlurForLockState(float blur) {
732 if (!IsBlurAllowedForLockState())
733 return;
734
735 // |is_wallpaper_blurrred_for_lock_state_| may already be updated in
736 // InstallDesktopController. Always try to update, then invoke observer
737 // if something changed.
738 for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
739 root_window_controller->wallpaper_widget_controller()->SetWallpaperBlur(
740 blur, kLockAnimationBlurAnimationDuration);
741 }
742
743 DCHECK(is_wallpaper_blurred_for_lock_state_);
744 is_wallpaper_blurred_for_lock_state_ = false;
745 for (auto& observer : observers_)
746 observer.OnWallpaperBlurChanged();
747 }
748
ShouldApplyColorFilter() const749 bool WallpaperControllerImpl::ShouldApplyColorFilter() const {
750 // Apply a color filter on the wallpaper in a blocked user session or overview
751 // or in tablet mode unless during wallpaper preview.
752 const bool should_dim =
753 Shell::Get()->session_controller()->IsUserSessionBlocked() ||
754 Shell::Get()->overview_controller()->InOverviewSession() ||
755 (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
756 !confirm_preview_wallpaper_callback_);
757 return should_dim && !IsOneShotWallpaper();
758 }
759
IsBlurAllowedForLockState() const760 bool WallpaperControllerImpl::IsBlurAllowedForLockState() const {
761 return !IsDevicePolicyWallpaper() && !IsOneShotWallpaper();
762 }
763
SetUserWallpaperInfo(const AccountId & account_id,const WallpaperInfo & info)764 bool WallpaperControllerImpl::SetUserWallpaperInfo(const AccountId& account_id,
765 const WallpaperInfo& info) {
766 if (IsEphemeralUser(account_id)) {
767 ephemeral_users_wallpaper_info_[account_id] = info;
768 return true;
769 }
770
771 if (!local_state_)
772 return false;
773
774 WallpaperInfo old_info;
775 if (GetUserWallpaperInfo(account_id, &old_info)) {
776 // Remove the color cache of the previous wallpaper if it exists.
777 DictionaryPrefUpdate wallpaper_colors_update(local_state_,
778 prefs::kWallpaperColors);
779 wallpaper_colors_update->RemoveKey(old_info.location);
780 }
781
782 DictionaryPrefUpdate wallpaper_update(local_state_,
783 prefs::kUserWallpaperInfo);
784 auto wallpaper_info_dict = std::make_unique<base::DictionaryValue>();
785 wallpaper_info_dict->SetString(
786 kNewWallpaperDateNodeName,
787 base::NumberToString(info.date.ToInternalValue()));
788 wallpaper_info_dict->SetString(kNewWallpaperLocationNodeName, info.location);
789 wallpaper_info_dict->SetInteger(kNewWallpaperLayoutNodeName, info.layout);
790 wallpaper_info_dict->SetInteger(kNewWallpaperTypeNodeName, info.type);
791 wallpaper_update->SetWithoutPathExpansion(account_id.GetUserEmail(),
792 std::move(wallpaper_info_dict));
793 return true;
794 }
795
GetUserWallpaperInfo(const AccountId & account_id,WallpaperInfo * info) const796 bool WallpaperControllerImpl::GetUserWallpaperInfo(const AccountId& account_id,
797 WallpaperInfo* info) const {
798 if (IsEphemeralUser(account_id)) {
799 // Ephemeral users do not save anything to local state. Return true if the
800 // info can be found in the map, otherwise return false.
801 auto it = ephemeral_users_wallpaper_info_.find(account_id);
802 if (it == ephemeral_users_wallpaper_info_.end())
803 return false;
804
805 *info = it->second;
806 return true;
807 }
808
809 if (!local_state_)
810 return false;
811 const base::DictionaryValue* info_dict;
812 if (!local_state_->GetDictionary(prefs::kUserWallpaperInfo)
813 ->GetDictionaryWithoutPathExpansion(account_id.GetUserEmail(),
814 &info_dict)) {
815 return false;
816 }
817
818 // Use temporary variables to keep |info| untouched in the error case.
819 std::string location;
820 if (!info_dict->GetString(kNewWallpaperLocationNodeName, &location))
821 return false;
822 int layout;
823 if (!info_dict->GetInteger(kNewWallpaperLayoutNodeName, &layout))
824 return false;
825 int type;
826 if (!info_dict->GetInteger(kNewWallpaperTypeNodeName, &type))
827 return false;
828 std::string date_string;
829 if (!info_dict->GetString(kNewWallpaperDateNodeName, &date_string))
830 return false;
831 int64_t date_val;
832 if (!base::StringToInt64(date_string, &date_val))
833 return false;
834
835 info->location = location;
836 info->layout = static_cast<WallpaperLayout>(layout);
837 info->type = static_cast<WallpaperType>(type);
838 info->date = base::Time::FromInternalValue(date_val);
839 return true;
840 }
841
GetWallpaperFromCache(const AccountId & account_id,gfx::ImageSkia * image)842 bool WallpaperControllerImpl::GetWallpaperFromCache(const AccountId& account_id,
843 gfx::ImageSkia* image) {
844 CustomWallpaperMap::const_iterator it = wallpaper_cache_map_.find(account_id);
845 if (it != wallpaper_cache_map_.end() && !it->second.second.isNull()) {
846 *image = it->second.second;
847 return true;
848 }
849 return false;
850 }
851
GetPathFromCache(const AccountId & account_id,base::FilePath * path)852 bool WallpaperControllerImpl::GetPathFromCache(const AccountId& account_id,
853 base::FilePath* path) {
854 CustomWallpaperMap::const_iterator it = wallpaper_cache_map_.find(account_id);
855 if (it != wallpaper_cache_map_.end()) {
856 *path = it->second.first;
857 return true;
858 }
859 return false;
860 }
861
AddFirstWallpaperAnimationEndCallback(base::OnceClosure callback,aura::Window * window)862 void WallpaperControllerImpl::AddFirstWallpaperAnimationEndCallback(
863 base::OnceClosure callback,
864 aura::Window* window) {
865 WallpaperWidgetController* wallpaper_widget_controller =
866 RootWindowController::ForWindow(window)->wallpaper_widget_controller();
867 if (!current_wallpaper_ ||
868 (is_first_wallpaper_ && wallpaper_widget_controller->IsAnimating())) {
869 // No wallpaper has been set, or the first wallpaper is still animating.
870 wallpaper_widget_controller->AddAnimationEndCallback(std::move(callback));
871 } else {
872 std::move(callback).Run();
873 }
874 }
875
StartDecodeFromPath(const AccountId & account_id,const base::FilePath & wallpaper_path,const WallpaperInfo & info,bool show_wallpaper)876 void WallpaperControllerImpl::StartDecodeFromPath(
877 const AccountId& account_id,
878 const base::FilePath& wallpaper_path,
879 const WallpaperInfo& info,
880 bool show_wallpaper) {
881 ReadAndDecodeWallpaper(
882 base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
883 weak_factory_.GetWeakPtr(), account_id, wallpaper_path,
884 info, show_wallpaper),
885 sequenced_task_runner_, wallpaper_path);
886 }
887
SetClient(WallpaperControllerClient * client)888 void WallpaperControllerImpl::SetClient(WallpaperControllerClient* client) {
889 wallpaper_controller_client_ = client;
890 }
891
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)892 void WallpaperControllerImpl::Init(
893 const base::FilePath& user_data_path,
894 const base::FilePath& chromeos_wallpapers_path,
895 const base::FilePath& chromeos_custom_wallpapers_path,
896 const base::FilePath& device_policy_wallpaper_path) {
897 SetGlobalUserDataDir(user_data_path);
898 SetGlobalChromeOSWallpapersDir(chromeos_wallpapers_path);
899 SetGlobalChromeOSCustomWallpapersDir(chromeos_custom_wallpapers_path);
900 SetDevicePolicyWallpaperPath(device_policy_wallpaper_path);
901 }
902
SetCustomWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id,const std::string & file_name,WallpaperLayout layout,const gfx::ImageSkia & image,bool preview_mode)903 void WallpaperControllerImpl::SetCustomWallpaper(
904 const AccountId& account_id,
905 const std::string& wallpaper_files_id,
906 const std::string& file_name,
907 WallpaperLayout layout,
908 const gfx::ImageSkia& image,
909 bool preview_mode) {
910 DCHECK(Shell::Get()->session_controller()->IsActiveUserSessionStarted());
911 if (!CanSetUserWallpaper(account_id))
912 return;
913
914 const bool is_active_user = IsActiveUser(account_id);
915 if (preview_mode) {
916 DCHECK(is_active_user);
917 confirm_preview_wallpaper_callback_ =
918 base::BindOnce(&WallpaperControllerImpl::SaveAndSetWallpaper,
919 weak_factory_.GetWeakPtr(), account_id,
920 wallpaper_files_id, file_name, CUSTOMIZED, layout,
921 /*show_wallpaper=*/false, image);
922 reload_preview_wallpaper_callback_ =
923 base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
924 weak_factory_.GetWeakPtr(), image,
925 WallpaperInfo{std::string(), layout, CUSTOMIZED,
926 base::Time::Now().LocalMidnight()},
927 /*preview_mode=*/true, /*always_on_top=*/false);
928 // Show the preview wallpaper.
929 reload_preview_wallpaper_callback_.Run();
930 } else {
931 SaveAndSetWallpaper(account_id, wallpaper_files_id, file_name, CUSTOMIZED,
932 layout, /*show_wallpaper=*/is_active_user, image);
933 }
934 }
935
SetOnlineWallpaperIfExists(const AccountId & account_id,const std::string & url,WallpaperLayout layout,bool preview_mode,SetOnlineWallpaperIfExistsCallback callback)936 void WallpaperControllerImpl::SetOnlineWallpaperIfExists(
937 const AccountId& account_id,
938 const std::string& url,
939 WallpaperLayout layout,
940 bool preview_mode,
941 SetOnlineWallpaperIfExistsCallback callback) {
942 DCHECK(Shell::Get()->session_controller()->IsActiveUserSessionStarted());
943 DCHECK(CanSetUserWallpaper(account_id));
944
945 const OnlineWallpaperParams params = {account_id, url, layout, preview_mode};
946 base::PostTaskAndReplyWithResult(
947 sequenced_task_runner_.get(), FROM_HERE,
948 base::BindOnce(&GetExistingOnlineWallpaperPath, url),
949 base::BindOnce(&WallpaperControllerImpl::SetOnlineWallpaperFromPath,
950 weak_factory_.GetWeakPtr(), std::move(callback), params));
951 }
952
SetOnlineWallpaperFromData(const AccountId & account_id,const std::string & image_data,const std::string & url,WallpaperLayout layout,bool preview_mode,SetOnlineWallpaperFromDataCallback callback)953 void WallpaperControllerImpl::SetOnlineWallpaperFromData(
954 const AccountId& account_id,
955 const std::string& image_data,
956 const std::string& url,
957 WallpaperLayout layout,
958 bool preview_mode,
959 SetOnlineWallpaperFromDataCallback callback) {
960 if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted() ||
961 !CanSetUserWallpaper(account_id)) {
962 std::move(callback).Run(/*success=*/false);
963 return;
964 }
965
966 const OnlineWallpaperParams params = {account_id, url, layout, preview_mode};
967 LoadedCallback decoded_callback =
968 base::BindOnce(&WallpaperControllerImpl::OnOnlineWallpaperDecoded,
969 weak_factory_.GetWeakPtr(), params, /*save_file=*/true,
970 std::move(callback));
971 if (bypass_decode_for_testing_) {
972 std::move(decoded_callback)
973 .Run(CreateSolidColorWallpaper(kDefaultWallpaperColor));
974 return;
975 }
976 // Use default codec because 1) online wallpapers may have various formats,
977 // 2) the image data comes from the Chrome OS wallpaper picker and is
978 // trusted (third-party wallpaper apps use |SetThirdPartyWallpaper|), 3) the
979 // code path is never used on login screen (enforced by the check above).
980 DecodeWallpaper(image_data, data_decoder::mojom::ImageCodec::DEFAULT,
981 std::move(decoded_callback));
982 }
983
SetDefaultWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id,bool show_wallpaper)984 void WallpaperControllerImpl::SetDefaultWallpaper(
985 const AccountId& account_id,
986 const std::string& wallpaper_files_id,
987 bool show_wallpaper) {
988 if (!CanSetUserWallpaper(account_id))
989 return;
990
991 RemoveUserWallpaper(account_id, wallpaper_files_id);
992 if (!InitializeUserWallpaperInfo(account_id)) {
993 LOG(ERROR) << "Initializing user wallpaper info fails. This should never "
994 "happen except in tests.";
995 }
996 if (show_wallpaper)
997 SetDefaultWallpaperImpl(account_id, /*show_wallpaper=*/true);
998 }
999
SetCustomizedDefaultWallpaperPaths(const base::FilePath & customized_default_small_path,const base::FilePath & customized_default_large_path)1000 void WallpaperControllerImpl::SetCustomizedDefaultWallpaperPaths(
1001 const base::FilePath& customized_default_small_path,
1002 const base::FilePath& customized_default_large_path) {
1003 customized_default_small_path_ = customized_default_small_path;
1004 customized_default_large_path_ = customized_default_large_path;
1005
1006 // If the current wallpaper has type DEFAULT, the new customized default
1007 // wallpaper should be shown immediately to update the screen. It shouldn't
1008 // replace wallpapers of other types.
1009 bool show_wallpaper = (GetWallpaperType() == DEFAULT);
1010
1011 // Customized default wallpapers are subject to the same restrictions as other
1012 // default wallpapers, e.g. they should not be set during guest sessions.
1013 SetDefaultWallpaperImpl(EmptyAccountId(), show_wallpaper);
1014 }
1015
SetPolicyWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id,const std::string & data)1016 void WallpaperControllerImpl::SetPolicyWallpaper(
1017 const AccountId& account_id,
1018 const std::string& wallpaper_files_id,
1019 const std::string& data) {
1020 // There is no visible wallpaper in kiosk mode.
1021 if (IsInKioskMode())
1022 return;
1023
1024 // Updates the screen only when the user with this account_id has logged in.
1025 const bool show_wallpaper = IsActiveUser(account_id);
1026 LoadedCallback callback = base::BindOnce(
1027 &WallpaperControllerImpl::SaveAndSetWallpaper, weak_factory_.GetWeakPtr(),
1028 account_id, wallpaper_files_id, kPolicyWallpaperFile, POLICY,
1029 WALLPAPER_LAYOUT_CENTER_CROPPED, show_wallpaper);
1030
1031 if (bypass_decode_for_testing_) {
1032 std::move(callback).Run(CreateSolidColorWallpaper(kDefaultWallpaperColor));
1033 return;
1034 }
1035 DecodeWallpaper(data, data_decoder::mojom::ImageCodec::DEFAULT,
1036 std::move(callback));
1037 }
1038
SetDevicePolicyWallpaperPath(const base::FilePath & device_policy_wallpaper_path)1039 void WallpaperControllerImpl::SetDevicePolicyWallpaperPath(
1040 const base::FilePath& device_policy_wallpaper_path) {
1041 const bool was_device_policy_wallpaper_enforced =
1042 !device_policy_wallpaper_path_.empty();
1043 device_policy_wallpaper_path_ = device_policy_wallpaper_path;
1044 if (ShouldSetDevicePolicyWallpaper()) {
1045 SetDevicePolicyWallpaper();
1046 } else if (was_device_policy_wallpaper_enforced &&
1047 device_policy_wallpaper_path.empty()) {
1048 // If the device wallpaper policy is cleared, the wallpaper should revert to
1049 // the wallpaper of the current user with the large pod in the users list in
1050 // the login screen. If there is no such user, use the first user in the
1051 // users list.
1052 // TODO(xdai): Get the account id from the session controller and then call
1053 // ShowUserWallpaper() to display it.
1054 }
1055 }
1056
SetThirdPartyWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id,const std::string & file_name,WallpaperLayout layout,const gfx::ImageSkia & image)1057 bool WallpaperControllerImpl::SetThirdPartyWallpaper(
1058 const AccountId& account_id,
1059 const std::string& wallpaper_files_id,
1060 const std::string& file_name,
1061 WallpaperLayout layout,
1062 const gfx::ImageSkia& image) {
1063 bool allowed_to_set_wallpaper = CanSetUserWallpaper(account_id);
1064 bool allowed_to_show_wallpaper = IsActiveUser(account_id);
1065
1066 if (allowed_to_set_wallpaper) {
1067 SaveAndSetWallpaper(account_id, wallpaper_files_id, file_name, CUSTOMIZED,
1068 layout, allowed_to_show_wallpaper, image);
1069 }
1070 return allowed_to_set_wallpaper && allowed_to_show_wallpaper;
1071 }
1072
ConfirmPreviewWallpaper()1073 void WallpaperControllerImpl::ConfirmPreviewWallpaper() {
1074 if (!confirm_preview_wallpaper_callback_) {
1075 DCHECK(!reload_preview_wallpaper_callback_);
1076 return;
1077 }
1078 std::move(confirm_preview_wallpaper_callback_).Run();
1079 reload_preview_wallpaper_callback_.Reset();
1080
1081 // Ensure color filter is applied after confirming the preview wallpaper.
1082 if (ShouldApplyColorFilter())
1083 RepaintWallpaper();
1084
1085 for (auto& observer : observers_)
1086 observer.OnWallpaperPreviewEnded();
1087 }
1088
CancelPreviewWallpaper()1089 void WallpaperControllerImpl::CancelPreviewWallpaper() {
1090 if (!confirm_preview_wallpaper_callback_) {
1091 DCHECK(!reload_preview_wallpaper_callback_);
1092 return;
1093 }
1094 confirm_preview_wallpaper_callback_.Reset();
1095 reload_preview_wallpaper_callback_.Reset();
1096 ReloadWallpaper(/*clear_cache=*/false);
1097 for (auto& observer : observers_)
1098 observer.OnWallpaperPreviewEnded();
1099 }
1100
UpdateCustomWallpaperLayout(const AccountId & account_id,WallpaperLayout layout)1101 void WallpaperControllerImpl::UpdateCustomWallpaperLayout(
1102 const AccountId& account_id,
1103 WallpaperLayout layout) {
1104 // This method has a very specific use case: the user should be active and
1105 // have a custom wallpaper.
1106 if (!IsActiveUser(account_id))
1107 return;
1108
1109 WallpaperInfo info;
1110 if (!GetUserWallpaperInfo(account_id, &info) || info.type != CUSTOMIZED)
1111 return;
1112 if (info.layout == layout)
1113 return;
1114
1115 info.layout = layout;
1116 if (!SetUserWallpaperInfo(account_id, info)) {
1117 LOG(ERROR) << "Setting user wallpaper info fails. This should never happen "
1118 "except in tests.";
1119 }
1120 ShowUserWallpaper(account_id);
1121 }
1122
ShowUserWallpaper(const AccountId & account_id)1123 void WallpaperControllerImpl::ShowUserWallpaper(const AccountId& account_id) {
1124 current_user_ = account_id;
1125 const user_manager::UserType user_type = GetUserType(account_id);
1126 if (user_type == user_manager::USER_TYPE_KIOSK_APP ||
1127 user_type == user_manager::USER_TYPE_ARC_KIOSK_APP) {
1128 return;
1129 }
1130
1131 if (ShouldSetDevicePolicyWallpaper()) {
1132 SetDevicePolicyWallpaper();
1133 return;
1134 }
1135
1136 WallpaperInfo info;
1137 if (!GetUserWallpaperInfo(account_id, &info)) {
1138 if (!InitializeUserWallpaperInfo(account_id))
1139 return;
1140 GetUserWallpaperInfo(account_id, &info);
1141 }
1142
1143 // For ephemeral users, the cache is the only place to access their wallpaper
1144 // because it is not saved to disk. If the image doesn't exist in cache, it
1145 // means the user's wallpaper type is default (i.e. the user never sets their
1146 // own wallpaper), and it's a bug if it's not.
1147 //
1148 // For regular users, the image will be read from disk if the cache is not
1149 // hit (e.g. when the first time the wallpaper is shown on login screen).
1150 gfx::ImageSkia user_wallpaper;
1151 if (GetWallpaperFromCache(account_id, &user_wallpaper)) {
1152 ShowWallpaperImage(user_wallpaper, info, /*preview_mode=*/false,
1153 /*always_on_top=*/false);
1154 return;
1155 }
1156
1157 if (info.type == DEFAULT) {
1158 SetDefaultWallpaperImpl(account_id, /*show_wallpaper=*/true);
1159 return;
1160 }
1161
1162 if (info.type != CUSTOMIZED && info.type != POLICY && info.type != DEVICE) {
1163 // Load wallpaper according to WallpaperInfo.
1164 SetWallpaperFromInfo(account_id, info, /*show_wallpaper=*/true);
1165 return;
1166 }
1167
1168 base::FilePath wallpaper_path;
1169 if (info.type == DEVICE) {
1170 DCHECK(!device_policy_wallpaper_path_.empty());
1171 wallpaper_path = device_policy_wallpaper_path_;
1172 } else {
1173 std::string sub_dir = GetCustomWallpaperSubdirForCurrentResolution();
1174 // Wallpaper is not resized when layout is
1175 // WALLPAPER_LAYOUT_CENTER.
1176 // Original wallpaper should be used in this case.
1177 if (info.layout == WALLPAPER_LAYOUT_CENTER)
1178 sub_dir = kOriginalWallpaperSubDir;
1179 wallpaper_path = GetCustomWallpaperDir(sub_dir).Append(info.location);
1180 }
1181
1182 CustomWallpaperMap::iterator it = wallpaper_cache_map_.find(account_id);
1183 // Do not try to load the wallpaper if the path is the same, since loading
1184 // could still be in progress. We ignore the existence of the image.
1185 if (it != wallpaper_cache_map_.end() && it->second.first == wallpaper_path)
1186 return;
1187
1188 // Set the new path and reset the existing image - the image will be
1189 // added once it becomes available.
1190 wallpaper_cache_map_[account_id] =
1191 CustomWallpaperElement(wallpaper_path, gfx::ImageSkia());
1192
1193 sequenced_task_runner_->PostTask(
1194 FROM_HERE,
1195 base::BindOnce(&SetWallpaperFromPath, account_id, info, wallpaper_path,
1196 /*show_wallpaper=*/true,
1197 base::ThreadTaskRunnerHandle::Get(),
1198 weak_factory_.GetWeakPtr()));
1199 }
1200
ShowSigninWallpaper()1201 void WallpaperControllerImpl::ShowSigninWallpaper() {
1202 current_user_ = EmptyAccountId();
1203 if (ShouldSetDevicePolicyWallpaper())
1204 SetDevicePolicyWallpaper();
1205 else
1206 SetDefaultWallpaperImpl(EmptyAccountId(), /*show_wallpaper=*/true);
1207 }
1208
ShowOneShotWallpaper(const gfx::ImageSkia & image)1209 void WallpaperControllerImpl::ShowOneShotWallpaper(
1210 const gfx::ImageSkia& image) {
1211 const WallpaperInfo info = {
1212 std::string(), WallpaperLayout::WALLPAPER_LAYOUT_STRETCH,
1213 WallpaperType::ONE_SHOT, base::Time::Now().LocalMidnight()};
1214 ShowWallpaperImage(image, info, /*preview_mode=*/false,
1215 /*always_on_top=*/false);
1216 }
1217
ShowAlwaysOnTopWallpaper(const base::FilePath & image_path)1218 void WallpaperControllerImpl::ShowAlwaysOnTopWallpaper(
1219 const base::FilePath& image_path) {
1220 is_always_on_top_wallpaper_ = true;
1221 const WallpaperInfo info = {
1222 std::string(), WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
1223 WallpaperType::ONE_SHOT, base::Time::Now().LocalMidnight()};
1224 ReparentWallpaper(GetWallpaperContainerId(locked_));
1225 ReadAndDecodeWallpaper(
1226 base::BindOnce(&WallpaperControllerImpl::OnAlwaysOnTopWallpaperDecoded,
1227 weak_factory_.GetWeakPtr(), info),
1228 sequenced_task_runner_, image_path);
1229 }
1230
RemoveAlwaysOnTopWallpaper()1231 void WallpaperControllerImpl::RemoveAlwaysOnTopWallpaper() {
1232 if (!is_always_on_top_wallpaper_) {
1233 DCHECK(!reload_always_on_top_wallpaper_callback_);
1234 return;
1235 }
1236 is_always_on_top_wallpaper_ = false;
1237 reload_always_on_top_wallpaper_callback_.Reset();
1238 ReparentWallpaper(GetWallpaperContainerId(locked_));
1239 // Forget current wallpaper data.
1240 current_wallpaper_.reset();
1241 ReloadWallpaper(/*clear_cache=*/false);
1242 }
1243
RemoveUserWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id)1244 void WallpaperControllerImpl::RemoveUserWallpaper(
1245 const AccountId& account_id,
1246 const std::string& wallpaper_files_id) {
1247 RemoveUserWallpaperInfo(account_id);
1248 RemoveUserWallpaperImpl(account_id, wallpaper_files_id);
1249 }
1250
RemovePolicyWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id)1251 void WallpaperControllerImpl::RemovePolicyWallpaper(
1252 const AccountId& account_id,
1253 const std::string& wallpaper_files_id) {
1254 if (!IsPolicyControlled(account_id))
1255 return;
1256
1257 // Updates the screen only when the user has logged in.
1258 const bool show_wallpaper =
1259 Shell::Get()->session_controller()->IsActiveUserSessionStarted();
1260 // Removes the wallpaper info so that the user is no longer policy controlled,
1261 // otherwise setting default wallpaper is not allowed.
1262 RemoveUserWallpaperInfo(account_id);
1263 SetDefaultWallpaper(account_id, wallpaper_files_id, show_wallpaper);
1264 }
1265
GetOfflineWallpaperList(GetOfflineWallpaperListCallback callback)1266 void WallpaperControllerImpl::GetOfflineWallpaperList(
1267 GetOfflineWallpaperListCallback callback) {
1268 base::PostTaskAndReplyWithResult(sequenced_task_runner_.get(), FROM_HERE,
1269 base::BindOnce(&GetOfflineWallpaperListImpl),
1270 std::move(callback));
1271 }
1272
SetAnimationDuration(base::TimeDelta animation_duration)1273 void WallpaperControllerImpl::SetAnimationDuration(
1274 base::TimeDelta animation_duration) {
1275 animation_duration_ = animation_duration;
1276 }
1277
OpenWallpaperPickerIfAllowed()1278 void WallpaperControllerImpl::OpenWallpaperPickerIfAllowed() {
1279 if (wallpaper_controller_client_ && CanOpenWallpaperPicker())
1280 wallpaper_controller_client_->OpenWallpaperPicker();
1281 }
1282
MinimizeInactiveWindows(const std::string & user_id_hash)1283 void WallpaperControllerImpl::MinimizeInactiveWindows(
1284 const std::string& user_id_hash) {
1285 if (!window_state_manager_)
1286 window_state_manager_ = std::make_unique<WallpaperWindowStateManager>();
1287
1288 window_state_manager_->MinimizeInactiveWindows(user_id_hash);
1289 }
1290
RestoreMinimizedWindows(const std::string & user_id_hash)1291 void WallpaperControllerImpl::RestoreMinimizedWindows(
1292 const std::string& user_id_hash) {
1293 if (!window_state_manager_) {
1294 NOTREACHED() << "This should only be called after calling "
1295 << "MinimizeInactiveWindows.";
1296 return;
1297 }
1298 window_state_manager_->RestoreMinimizedWindows(user_id_hash);
1299 }
1300
AddObserver(WallpaperControllerObserver * observer)1301 void WallpaperControllerImpl::AddObserver(
1302 WallpaperControllerObserver* observer) {
1303 observers_.AddObserver(observer);
1304 }
1305
RemoveObserver(WallpaperControllerObserver * observer)1306 void WallpaperControllerImpl::RemoveObserver(
1307 WallpaperControllerObserver* observer) {
1308 observers_.RemoveObserver(observer);
1309 }
1310
GetWallpaperImage()1311 gfx::ImageSkia WallpaperControllerImpl::GetWallpaperImage() {
1312 return GetWallpaper();
1313 }
1314
GetWallpaperColors()1315 const std::vector<SkColor>& WallpaperControllerImpl::GetWallpaperColors() {
1316 return prominent_colors_;
1317 }
1318
IsWallpaperBlurredForLockState() const1319 bool WallpaperControllerImpl::IsWallpaperBlurredForLockState() const {
1320 return is_wallpaper_blurred_for_lock_state_;
1321 }
1322
IsActiveUserWallpaperControlledByPolicy()1323 bool WallpaperControllerImpl::IsActiveUserWallpaperControlledByPolicy() {
1324 const UserSession* const active_user_session = GetActiveUserSession();
1325 if (!active_user_session)
1326 return false;
1327 return IsPolicyControlled(active_user_session->user_info.account_id);
1328 }
1329
GetActiveUserWallpaperInfo()1330 WallpaperInfo WallpaperControllerImpl::GetActiveUserWallpaperInfo() {
1331 WallpaperInfo info;
1332 const UserSession* const active_user_session = GetActiveUserSession();
1333 if (!active_user_session ||
1334 !GetUserWallpaperInfo(active_user_session->user_info.account_id, &info)) {
1335 info.location = std::string();
1336 info.layout = NUM_WALLPAPER_LAYOUT;
1337 }
1338
1339 return info;
1340 }
1341
ShouldShowWallpaperSetting()1342 bool WallpaperControllerImpl::ShouldShowWallpaperSetting() {
1343 const UserSession* const active_user_session = GetActiveUserSession();
1344 if (!active_user_session)
1345 return false;
1346
1347 // Since everything gets wiped at the end of the Public Session (and Managed
1348 // Guest Session), users are disallowed to set wallpaper (and other
1349 // personalization settings) to avoid unnecessary confusion and surprise when
1350 // everything resets.
1351 user_manager::UserType active_user_type = active_user_session->user_info.type;
1352 return active_user_type == user_manager::USER_TYPE_REGULAR ||
1353 active_user_type == user_manager::USER_TYPE_SUPERVISED ||
1354 active_user_type == user_manager::USER_TYPE_CHILD;
1355 }
1356
OnDisplayConfigurationChanged()1357 void WallpaperControllerImpl::OnDisplayConfigurationChanged() {
1358 gfx::Size max_display_size = GetMaxDisplaySizeInNative();
1359 if (current_max_display_size_ == max_display_size)
1360 return;
1361
1362 current_max_display_size_ = max_display_size;
1363 if (wallpaper_mode_ == WALLPAPER_IMAGE && current_wallpaper_) {
1364 timer_.Stop();
1365 GetInternalDisplayCompositorLock();
1366 timer_.Start(
1367 FROM_HERE, wallpaper_reload_delay_,
1368 base::BindOnce(&WallpaperControllerImpl::ReloadWallpaper,
1369 weak_factory_.GetWeakPtr(), /*clear_cache=*/false));
1370 }
1371 }
1372
OnRootWindowAdded(aura::Window * root_window)1373 void WallpaperControllerImpl::OnRootWindowAdded(aura::Window* root_window) {
1374 // The wallpaper hasn't been set yet.
1375 if (wallpaper_mode_ == WALLPAPER_NONE)
1376 return;
1377
1378 // Handle resolution change for "built-in" images.
1379 gfx::Size max_display_size = GetMaxDisplaySizeInNative();
1380 if (current_max_display_size_ != max_display_size) {
1381 current_max_display_size_ = max_display_size;
1382 if (wallpaper_mode_ == WALLPAPER_IMAGE && current_wallpaper_)
1383 ReloadWallpaper(/*clear_cache=*/true);
1384 }
1385
1386 UpdateWallpaperForRootWindow(root_window, /*lock_state_changed=*/false,
1387 /*new_root=*/true);
1388 }
1389
OnShellInitialized()1390 void WallpaperControllerImpl::OnShellInitialized() {
1391 Shell::Get()->tablet_mode_controller()->AddObserver(this);
1392 Shell::Get()->overview_controller()->AddObserver(this);
1393 }
1394
OnShellDestroying()1395 void WallpaperControllerImpl::OnShellDestroying() {
1396 Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
1397 Shell::Get()->overview_controller()->RemoveObserver(this);
1398 }
1399
OnWallpaperResized()1400 void WallpaperControllerImpl::OnWallpaperResized() {
1401 CalculateWallpaperColors();
1402 compositor_lock_.reset();
1403 }
1404
OnColorCalculationComplete()1405 void WallpaperControllerImpl::OnColorCalculationComplete() {
1406 const std::vector<SkColor> colors = color_calculator_->prominent_colors();
1407 color_calculator_.reset();
1408 // Use |WallpaperInfo::location| as the key for storing |prominent_colors_| in
1409 // the |kWallpaperColors| pref.
1410 // TODO(crbug.com/787134): The |prominent_colors_| of wallpapers with empty
1411 // location should be cached as well.
1412 if (!current_wallpaper_->wallpaper_info().location.empty()) {
1413 CacheProminentColors(colors, current_wallpaper_->wallpaper_info().location);
1414 }
1415 SetProminentColors(colors);
1416 }
1417
OnSessionStateChanged(session_manager::SessionState state)1418 void WallpaperControllerImpl::OnSessionStateChanged(
1419 session_manager::SessionState state) {
1420 // Replace the device policy wallpaper with a user wallpaper if necessary.
1421 if (IsDevicePolicyWallpaper() && !ShouldSetDevicePolicyWallpaper())
1422 ReloadWallpaper(/*clear_cache=*/false);
1423
1424 CalculateWallpaperColors();
1425
1426 locked_ = state != session_manager::SessionState::ACTIVE;
1427
1428 // The wallpaper may be dimmed/blurred based on session state. The color of
1429 // the dimming overlay depends on the prominent color cached from a previous
1430 // calculation, or a default color if cache is not available. It should never
1431 // depend on any in-flight color calculation.
1432 if (wallpaper_mode_ == WALLPAPER_IMAGE &&
1433 (state == session_manager::SessionState::ACTIVE ||
1434 state == session_manager::SessionState::LOCKED ||
1435 state == session_manager::SessionState::LOGIN_SECONDARY)) {
1436 UpdateWallpaperForAllRootWindows(/*lock_state_changed=*/true);
1437 } else {
1438 // Just update container.
1439 ReparentWallpaper(GetWallpaperContainerId(locked_));
1440 }
1441 }
1442
OnTabletModeStarted()1443 void WallpaperControllerImpl::OnTabletModeStarted() {
1444 RepaintWallpaper();
1445 }
1446
OnTabletModeEnded()1447 void WallpaperControllerImpl::OnTabletModeEnded() {
1448 RepaintWallpaper();
1449 }
1450
OnOverviewModeWillStart()1451 void WallpaperControllerImpl::OnOverviewModeWillStart() {
1452 // Due to visual glitches when overview mode is activated whilst wallpaper
1453 // preview is active (http://crbug.com/895265), cancel wallpaper preview and
1454 // close its front-end before toggling overview mode.
1455 MaybeClosePreviewWallpaper();
1456 }
1457
CompositorLockTimedOut()1458 void WallpaperControllerImpl::CompositorLockTimedOut() {
1459 compositor_lock_.reset();
1460 }
1461
ShowDefaultWallpaperForTesting()1462 void WallpaperControllerImpl::ShowDefaultWallpaperForTesting() {
1463 SetDefaultWallpaperImpl(EmptyAccountId(), /*show_wallpaper=*/true);
1464 }
1465
CreateEmptyWallpaperForTesting()1466 void WallpaperControllerImpl::CreateEmptyWallpaperForTesting() {
1467 ResetProminentColors();
1468 current_wallpaper_.reset();
1469 wallpaper_mode_ = WALLPAPER_IMAGE;
1470 UpdateWallpaperForAllRootWindows(/*lock_state_changed=*/false);
1471 }
1472
ReloadWallpaperForTesting(bool clear_cache)1473 void WallpaperControllerImpl::ReloadWallpaperForTesting(bool clear_cache) {
1474 ReloadWallpaper(clear_cache);
1475 }
1476
UpdateWallpaperForRootWindow(aura::Window * root_window,bool lock_state_changed,bool new_root)1477 void WallpaperControllerImpl::UpdateWallpaperForRootWindow(
1478 aura::Window* root_window,
1479 bool lock_state_changed,
1480 bool new_root) {
1481 DCHECK_EQ(WALLPAPER_IMAGE, wallpaper_mode_);
1482
1483 auto* wallpaper_widget_controller =
1484 RootWindowController::ForWindow(root_window)
1485 ->wallpaper_widget_controller();
1486 float blur = wallpaper_widget_controller->GetWallpaperBlur();
1487
1488 if (lock_state_changed || new_root) {
1489 const bool is_wallpaper_blurred_for_lock_state =
1490 Shell::Get()->session_controller()->IsUserSessionBlocked() &&
1491 IsBlurAllowedForLockState();
1492 if (is_wallpaper_blurred_for_lock_state_ !=
1493 is_wallpaper_blurred_for_lock_state) {
1494 is_wallpaper_blurred_for_lock_state_ =
1495 is_wallpaper_blurred_for_lock_state;
1496 for (auto& observer : observers_)
1497 observer.OnWallpaperBlurChanged();
1498 }
1499 const int container_id = GetWallpaperContainerId(locked_);
1500 wallpaper_widget_controller->Reparent(container_id);
1501
1502 blur = is_wallpaper_blurred_for_lock_state
1503 ? wallpaper_constants::kLockLoginBlur
1504 : wallpaper_constants::kClear;
1505 }
1506
1507 wallpaper_widget_controller->wallpaper_view()->ClearCachedImage();
1508 wallpaper_widget_controller->SetWallpaperBlur(
1509 blur, new_root ? base::TimeDelta() : kWallpaperLoadAnimationDuration);
1510 }
1511
UpdateWallpaperForAllRootWindows(bool lock_state_changed)1512 void WallpaperControllerImpl::UpdateWallpaperForAllRootWindows(
1513 bool lock_state_changed) {
1514 for (aura::Window* root : Shell::GetAllRootWindows())
1515 UpdateWallpaperForRootWindow(root, lock_state_changed, /*new_root=*/false);
1516 current_max_display_size_ = GetMaxDisplaySizeInNative();
1517 }
1518
ReparentWallpaper(int container)1519 bool WallpaperControllerImpl::ReparentWallpaper(int container) {
1520 bool moved = false;
1521 for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
1522 moved |= root_window_controller->wallpaper_widget_controller()->Reparent(
1523 container);
1524 }
1525 return moved;
1526 }
1527
GetWallpaperContainerId(bool locked)1528 int WallpaperControllerImpl::GetWallpaperContainerId(bool locked) {
1529 if (is_always_on_top_wallpaper_)
1530 return kShellWindowId_AlwaysOnTopWallpaperContainer;
1531
1532 return locked ? kShellWindowId_LockScreenWallpaperContainer
1533 : kShellWindowId_WallpaperContainer;
1534 }
1535
RemoveUserWallpaperInfo(const AccountId & account_id)1536 void WallpaperControllerImpl::RemoveUserWallpaperInfo(
1537 const AccountId& account_id) {
1538 if (wallpaper_cache_map_.find(account_id) != wallpaper_cache_map_.end())
1539 wallpaper_cache_map_.erase(account_id);
1540
1541 if (!local_state_)
1542 return;
1543 WallpaperInfo info;
1544 GetUserWallpaperInfo(account_id, &info);
1545 DictionaryPrefUpdate prefs_wallpapers_info_update(local_state_,
1546 prefs::kUserWallpaperInfo);
1547 prefs_wallpapers_info_update->RemoveKey(account_id.GetUserEmail());
1548 // Remove the color cache of the previous wallpaper if it exists.
1549 DictionaryPrefUpdate wallpaper_colors_update(local_state_,
1550 prefs::kWallpaperColors);
1551 wallpaper_colors_update->RemoveKey(info.location);
1552 }
1553
RemoveUserWallpaperImpl(const AccountId & account_id,const std::string & wallpaper_files_id)1554 void WallpaperControllerImpl::RemoveUserWallpaperImpl(
1555 const AccountId& account_id,
1556 const std::string& wallpaper_files_id) {
1557 if (wallpaper_files_id.empty())
1558 return;
1559
1560 std::vector<base::FilePath> files_to_remove;
1561
1562 // Remove small user wallpapers.
1563 base::FilePath wallpaper_path = GetCustomWallpaperDir(kSmallWallpaperSubDir);
1564 files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
1565
1566 // Remove large user wallpapers.
1567 wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
1568 files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
1569
1570 // Remove original user wallpapers.
1571 wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
1572 files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
1573
1574 base::ThreadPool::PostTask(
1575 FROM_HERE,
1576 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
1577 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
1578 base::BindOnce(&DeleteWallpaperInList, std::move(files_to_remove)));
1579 }
1580
SetDefaultWallpaperImpl(const AccountId & account_id,bool show_wallpaper)1581 void WallpaperControllerImpl::SetDefaultWallpaperImpl(
1582 const AccountId& account_id,
1583 bool show_wallpaper) {
1584 // There is no visible wallpaper in kiosk mode.
1585 if (IsInKioskMode())
1586 return;
1587
1588 wallpaper_cache_map_.erase(account_id);
1589
1590 const bool use_small =
1591 (GetAppropriateResolution() == WALLPAPER_RESOLUTION_SMALL);
1592 WallpaperLayout layout =
1593 use_small ? WALLPAPER_LAYOUT_CENTER : WALLPAPER_LAYOUT_CENTER_CROPPED;
1594 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1595 base::FilePath file_path;
1596 const user_manager::UserType user_type = GetUserType(account_id);
1597
1598 // The wallpaper is determined in the following order:
1599 // Guest wallpaper, child wallpaper, customized default wallpaper, and regular
1600 // default wallpaper.
1601 if (user_type == user_manager::USER_TYPE_GUEST) {
1602 const std::string switch_string =
1603 use_small ? chromeos::switches::kGuestWallpaperSmall
1604 : chromeos::switches::kGuestWallpaperLarge;
1605 file_path = command_line->GetSwitchValuePath(switch_string);
1606 } else if (user_type == user_manager::USER_TYPE_CHILD) {
1607 const std::string switch_string =
1608 use_small ? chromeos::switches::kChildWallpaperSmall
1609 : chromeos::switches::kChildWallpaperLarge;
1610 file_path = command_line->GetSwitchValuePath(switch_string);
1611 } else if (!customized_default_small_path_.empty()) {
1612 DCHECK(!customized_default_large_path_.empty());
1613 file_path = use_small ? customized_default_small_path_
1614 : customized_default_large_path_;
1615 } else {
1616 const std::string switch_string =
1617 use_small ? chromeos::switches::kDefaultWallpaperSmall
1618 : chromeos::switches::kDefaultWallpaperLarge;
1619 file_path = command_line->GetSwitchValuePath(switch_string);
1620 }
1621
1622 // We need to decode the image if there's no cache, or if the file path
1623 // doesn't match the cached value (i.e. the cache is outdated). Otherwise,
1624 // directly run the callback with the cached image.
1625 if (!cached_default_wallpaper_.image.isNull() &&
1626 cached_default_wallpaper_.file_path == file_path) {
1627 OnDefaultWallpaperDecoded(file_path, layout, show_wallpaper,
1628 cached_default_wallpaper_.image);
1629 } else {
1630 ReadAndDecodeWallpaper(
1631 base::BindOnce(&WallpaperControllerImpl::OnDefaultWallpaperDecoded,
1632 weak_factory_.GetWeakPtr(), file_path, layout,
1633 show_wallpaper),
1634 sequenced_task_runner_, file_path);
1635 }
1636 }
1637
CanSetUserWallpaper(const AccountId & account_id) const1638 bool WallpaperControllerImpl::CanSetUserWallpaper(
1639 const AccountId& account_id) const {
1640 // There is no visible wallpaper in kiosk mode.
1641 if (IsInKioskMode())
1642 return false;
1643 // Don't allow user wallpapers while policy is in effect.
1644 if (IsPolicyControlled(account_id))
1645 return false;
1646 return true;
1647 }
1648
WallpaperIsAlreadyLoaded(const gfx::ImageSkia & image,bool compare_layouts,WallpaperLayout layout) const1649 bool WallpaperControllerImpl::WallpaperIsAlreadyLoaded(
1650 const gfx::ImageSkia& image,
1651 bool compare_layouts,
1652 WallpaperLayout layout) const {
1653 if (!current_wallpaper_)
1654 return false;
1655
1656 // Compare layouts only if necessary.
1657 if (compare_layouts && layout != current_wallpaper_->wallpaper_info().layout)
1658 return false;
1659
1660 return WallpaperResizer::GetImageId(image) ==
1661 current_wallpaper_->original_image_id();
1662 }
1663
ReadAndDecodeWallpaper(LoadedCallback callback,scoped_refptr<base::SequencedTaskRunner> task_runner,const base::FilePath & file_path)1664 void WallpaperControllerImpl::ReadAndDecodeWallpaper(
1665 LoadedCallback callback,
1666 scoped_refptr<base::SequencedTaskRunner> task_runner,
1667 const base::FilePath& file_path) {
1668 decode_requests_for_testing_.push_back(file_path);
1669 if (bypass_decode_for_testing_) {
1670 std::move(callback).Run(CreateSolidColorWallpaper(kDefaultWallpaperColor));
1671 return;
1672 }
1673 std::string* data = new std::string;
1674 base::PostTaskAndReplyWithResult(
1675 task_runner.get(), FROM_HERE,
1676 base::BindOnce(&base::ReadFileToString, file_path, data),
1677 base::BindOnce(&OnWallpaperDataRead, std::move(callback),
1678 base::WrapUnique(data)));
1679 }
1680
InitializeUserWallpaperInfo(const AccountId & account_id)1681 bool WallpaperControllerImpl::InitializeUserWallpaperInfo(
1682 const AccountId& account_id) {
1683 const WallpaperInfo info = {std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED,
1684 DEFAULT, base::Time::Now().LocalMidnight()};
1685 return SetUserWallpaperInfo(account_id, info);
1686 }
1687
SetOnlineWallpaperFromPath(SetOnlineWallpaperIfExistsCallback callback,const OnlineWallpaperParams & params,const base::FilePath & file_path)1688 void WallpaperControllerImpl::SetOnlineWallpaperFromPath(
1689 SetOnlineWallpaperIfExistsCallback callback,
1690 const OnlineWallpaperParams& params,
1691 const base::FilePath& file_path) {
1692 bool file_exists = !file_path.empty();
1693 std::move(callback).Run(file_exists);
1694 if (file_exists) {
1695 ReadAndDecodeWallpaper(
1696 base::BindOnce(&WallpaperControllerImpl::OnOnlineWallpaperDecoded,
1697 weak_factory_.GetWeakPtr(), params, /*save_file=*/false,
1698 SetOnlineWallpaperFromDataCallback()),
1699 sequenced_task_runner_, file_path);
1700 }
1701 }
1702
OnOnlineWallpaperDecoded(const OnlineWallpaperParams & params,bool save_file,SetOnlineWallpaperFromDataCallback callback,const gfx::ImageSkia & image)1703 void WallpaperControllerImpl::OnOnlineWallpaperDecoded(
1704 const OnlineWallpaperParams& params,
1705 bool save_file,
1706 SetOnlineWallpaperFromDataCallback callback,
1707 const gfx::ImageSkia& image) {
1708 bool success = !image.isNull();
1709 if (callback)
1710 std::move(callback).Run(success);
1711 if (!success) {
1712 LOG(ERROR) << "Failed to decode online wallpaper.";
1713 return;
1714 }
1715
1716 if (save_file) {
1717 image.EnsureRepsForSupportedScales();
1718 gfx::ImageSkia deep_copy(image.DeepCopy());
1719 sequenced_task_runner_->PostTask(
1720 FROM_HERE, base::BindOnce(&SaveOnlineWallpaper, params.url,
1721 params.layout, deep_copy));
1722 }
1723
1724 const bool is_active_user = IsActiveUser(params.account_id);
1725 if (params.preview_mode) {
1726 DCHECK(is_active_user);
1727 confirm_preview_wallpaper_callback_ = base::BindOnce(
1728 &WallpaperControllerImpl::SetOnlineWallpaperImpl,
1729 weak_factory_.GetWeakPtr(), params, image, /*show_wallpaper=*/false);
1730 reload_preview_wallpaper_callback_ =
1731 base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
1732 weak_factory_.GetWeakPtr(), image,
1733 WallpaperInfo{params.url, params.layout, ONLINE,
1734 base::Time::Now().LocalMidnight()},
1735 /*preview_mode=*/true, /*always_on_top=*/false);
1736 // Show the preview wallpaper.
1737 reload_preview_wallpaper_callback_.Run();
1738 } else {
1739 SetOnlineWallpaperImpl(params, image, /*show_wallpaper=*/is_active_user);
1740 }
1741 }
1742
SetOnlineWallpaperImpl(const OnlineWallpaperParams & params,const gfx::ImageSkia & image,bool show_wallpaper)1743 void WallpaperControllerImpl::SetOnlineWallpaperImpl(
1744 const OnlineWallpaperParams& params,
1745 const gfx::ImageSkia& image,
1746 bool show_wallpaper) {
1747 WallpaperInfo wallpaper_info = {params.url, params.layout, ONLINE,
1748 base::Time::Now().LocalMidnight()};
1749 if (!SetUserWallpaperInfo(params.account_id, wallpaper_info)) {
1750 LOG(ERROR) << "Setting user wallpaper info fails. This should never happen "
1751 "except in tests.";
1752 }
1753 if (show_wallpaper) {
1754 ShowWallpaperImage(image, wallpaper_info, /*preview_mode=*/false,
1755 /*always_on_top=*/false);
1756 }
1757
1758 wallpaper_cache_map_[params.account_id] =
1759 CustomWallpaperElement(base::FilePath(), image);
1760 }
1761
SetWallpaperFromInfo(const AccountId & account_id,const WallpaperInfo & info,bool show_wallpaper)1762 void WallpaperControllerImpl::SetWallpaperFromInfo(const AccountId& account_id,
1763 const WallpaperInfo& info,
1764 bool show_wallpaper) {
1765 if (info.type != ONLINE && info.type != DEFAULT) {
1766 // This method is meant to be used for ONLINE and DEFAULT types. In
1767 // unexpected cases, revert to default wallpaper to fail safely. See
1768 // crosbug.com/38429.
1769 LOG(ERROR) << "Wallpaper reverts to default unexpected.";
1770 SetDefaultWallpaperImpl(account_id, show_wallpaper);
1771 return;
1772 }
1773
1774 // Do a sanity check that the file path is not empty.
1775 if (info.location.empty()) {
1776 // File name might be empty on debug configurations when stub users
1777 // were created directly in local state (for testing). Ignore such
1778 // errors i.e. allow such type of debug configurations on the desktop.
1779 LOG(WARNING) << "User wallpaper info is empty: " << account_id.Serialize();
1780 SetDefaultWallpaperImpl(account_id, show_wallpaper);
1781 return;
1782 }
1783
1784 base::FilePath wallpaper_path;
1785 if (info.type == ONLINE) {
1786 wallpaper_path =
1787 GetOnlineWallpaperPath(info.location, GetAppropriateResolution());
1788
1789 // If the wallpaper exists and it already contains the correct image we
1790 // can return immediately.
1791 CustomWallpaperMap::iterator it = wallpaper_cache_map_.find(account_id);
1792 if (it != wallpaper_cache_map_.end() &&
1793 it->second.first == wallpaper_path && !it->second.second.isNull())
1794 return;
1795
1796 ReadAndDecodeWallpaper(
1797 base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
1798 weak_factory_.GetWeakPtr(), account_id, wallpaper_path,
1799 info, show_wallpaper),
1800 sequenced_task_runner_, wallpaper_path);
1801 } else {
1802 // Default wallpapers are migrated from M21 user profiles. A code
1803 // refactor overlooked that case and caused these wallpapers not being
1804 // loaded at all. On some slow devices, it caused login webui not
1805 // visible after upgrade to M26 from M21. See crosbug.com/38429 for
1806 // details.
1807 DCHECK(!GlobalUserDataDir().empty());
1808 wallpaper_path = GlobalUserDataDir().Append(info.location);
1809
1810 ReadAndDecodeWallpaper(
1811 base::BindOnce(&WallpaperControllerImpl::OnWallpaperDecoded,
1812 weak_factory_.GetWeakPtr(), account_id, wallpaper_path,
1813 info, show_wallpaper),
1814 sequenced_task_runner_, wallpaper_path);
1815 }
1816 }
1817
OnDefaultWallpaperDecoded(const base::FilePath & path,WallpaperLayout layout,bool show_wallpaper,const gfx::ImageSkia & image)1818 void WallpaperControllerImpl::OnDefaultWallpaperDecoded(
1819 const base::FilePath& path,
1820 WallpaperLayout layout,
1821 bool show_wallpaper,
1822 const gfx::ImageSkia& image) {
1823 if (image.isNull()) {
1824 // Create a solid color wallpaper if the default wallpaper decoding fails.
1825 cached_default_wallpaper_.image =
1826 CreateSolidColorWallpaper(kDefaultWallpaperColor);
1827 cached_default_wallpaper_.file_path.clear();
1828 } else {
1829 cached_default_wallpaper_.image = image;
1830 cached_default_wallpaper_.file_path = path;
1831 }
1832
1833 if (show_wallpaper) {
1834 WallpaperInfo info(cached_default_wallpaper_.file_path.value(), layout,
1835 DEFAULT, base::Time::Now().LocalMidnight());
1836 ShowWallpaperImage(cached_default_wallpaper_.image, info,
1837 /*preview_mode=*/false, /*always_on_top=*/false);
1838 }
1839 }
1840
SaveAndSetWallpaper(const AccountId & account_id,const std::string & wallpaper_files_id,const std::string & file_name,WallpaperType type,WallpaperLayout layout,bool show_wallpaper,const gfx::ImageSkia & image)1841 void WallpaperControllerImpl::SaveAndSetWallpaper(
1842 const AccountId& account_id,
1843 const std::string& wallpaper_files_id,
1844 const std::string& file_name,
1845 WallpaperType type,
1846 WallpaperLayout layout,
1847 bool show_wallpaper,
1848 const gfx::ImageSkia& image) {
1849 // If the image of the new wallpaper is empty, the current wallpaper is still
1850 // kept instead of reverting to the default.
1851 if (image.isNull()) {
1852 LOG(ERROR) << "The wallpaper image is empty due to a decoding failure, or "
1853 "the client provided an empty image.";
1854 return;
1855 }
1856
1857 const std::string relative_path =
1858 base::FilePath(wallpaper_files_id).Append(file_name).value();
1859 // User's custom wallpaper path is determined by relative path and the
1860 // appropriate wallpaper resolution.
1861 WallpaperInfo info = {relative_path, layout, type,
1862 base::Time::Now().LocalMidnight()};
1863 if (!SetUserWallpaperInfo(account_id, info)) {
1864 LOG(ERROR) << "Setting user wallpaper info fails. This should never happen "
1865 "except in tests.";
1866 }
1867
1868 base::FilePath wallpaper_path =
1869 GetCustomWallpaperPath(WallpaperControllerImpl::kOriginalWallpaperSubDir,
1870 wallpaper_files_id, file_name);
1871
1872 const bool should_save_to_disk =
1873 !IsEphemeralUser(account_id) ||
1874 (type == POLICY &&
1875 GetUserType(account_id) == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
1876
1877 if (should_save_to_disk) {
1878 image.EnsureRepsForSupportedScales();
1879 gfx::ImageSkia deep_copy(image.DeepCopy());
1880 // Block shutdown on this task. Otherwise, we may lose the custom wallpaper
1881 // that the user selected.
1882 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
1883 base::ThreadPool::CreateSequencedTaskRunner(
1884 {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
1885 base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
1886 blocking_task_runner->PostTask(
1887 FROM_HERE, base::BindOnce(&SaveCustomWallpaper, wallpaper_files_id,
1888 wallpaper_path, layout, deep_copy));
1889 }
1890
1891 if (show_wallpaper) {
1892 ShowWallpaperImage(image, info, /*preview_mode=*/false,
1893 /*always_on_top=*/false);
1894 }
1895
1896 wallpaper_cache_map_[account_id] =
1897 CustomWallpaperElement(wallpaper_path, image);
1898 }
1899
OnWallpaperDecoded(const AccountId & account_id,const base::FilePath & path,const WallpaperInfo & info,bool show_wallpaper,const gfx::ImageSkia & image)1900 void WallpaperControllerImpl::OnWallpaperDecoded(const AccountId& account_id,
1901 const base::FilePath& path,
1902 const WallpaperInfo& info,
1903 bool show_wallpaper,
1904 const gfx::ImageSkia& image) {
1905 // Empty image indicates decode failure. Use default wallpaper in this case.
1906 if (image.isNull()) {
1907 LOG(ERROR) << "Failed to decode user wallpaper at " << path.value()
1908 << " Falls back to default wallpaper. ";
1909 SetDefaultWallpaperImpl(account_id, show_wallpaper);
1910 return;
1911 }
1912
1913 wallpaper_cache_map_[account_id] = CustomWallpaperElement(path, image);
1914 if (show_wallpaper) {
1915 ShowWallpaperImage(image, info, /*preview_mode=*/false,
1916 /*always_on_top=*/false);
1917 }
1918 }
1919
ReloadWallpaper(bool clear_cache)1920 void WallpaperControllerImpl::ReloadWallpaper(bool clear_cache) {
1921 const bool was_one_shot_wallpaper = IsOneShotWallpaper();
1922 const gfx::ImageSkia one_shot_wallpaper =
1923 was_one_shot_wallpaper
1924 ? current_wallpaper_->wallpaper_info().one_shot_wallpaper
1925 : gfx::ImageSkia();
1926 current_wallpaper_.reset();
1927 if (clear_cache)
1928 wallpaper_cache_map_.clear();
1929
1930 if (reload_always_on_top_wallpaper_callback_)
1931 reload_always_on_top_wallpaper_callback_.Run();
1932 else if (reload_preview_wallpaper_callback_)
1933 reload_preview_wallpaper_callback_.Run();
1934 else if (current_user_.is_valid())
1935 ShowUserWallpaper(current_user_);
1936 else if (was_one_shot_wallpaper)
1937 ShowOneShotWallpaper(one_shot_wallpaper);
1938 else
1939 ShowSigninWallpaper();
1940 }
1941
SetProminentColors(const std::vector<SkColor> & colors)1942 void WallpaperControllerImpl::SetProminentColors(
1943 const std::vector<SkColor>& colors) {
1944 if (prominent_colors_ == colors)
1945 return;
1946
1947 prominent_colors_ = colors;
1948 for (auto& observer : observers_)
1949 observer.OnWallpaperColorsChanged();
1950 }
1951
ResetProminentColors()1952 void WallpaperControllerImpl::ResetProminentColors() {
1953 static const std::vector<SkColor> kInvalidColors(color_profiles_.size(),
1954 kInvalidWallpaperColor);
1955 SetProminentColors(kInvalidColors);
1956 }
1957
CalculateWallpaperColors()1958 void WallpaperControllerImpl::CalculateWallpaperColors() {
1959 if (!current_wallpaper_)
1960 return;
1961
1962 // Cancel any in-flight color calculation.
1963 if (color_calculator_) {
1964 color_calculator_->RemoveObserver(this);
1965 color_calculator_.reset();
1966 }
1967
1968 // Fetch the color cache if it exists.
1969 if (!current_wallpaper_->wallpaper_info().location.empty()) {
1970 base::Optional<std::vector<SkColor>> cached_colors =
1971 GetCachedColors(current_wallpaper_->wallpaper_info().location);
1972 if (cached_colors.has_value()) {
1973 SetProminentColors(cached_colors.value());
1974 return;
1975 }
1976 }
1977
1978 // Color calculation is only allowed during an active session for performance
1979 // reasons. Observers outside an active session are notified of the cache, or
1980 // an invalid color if a previous calculation during active session failed.
1981 if (!ShouldCalculateColors()) {
1982 ResetProminentColors();
1983 return;
1984 }
1985
1986 color_calculator_ = std::make_unique<WallpaperColorCalculator>(
1987 GetWallpaper(), color_profiles_, sequenced_task_runner_);
1988 color_calculator_->AddObserver(this);
1989 if (!color_calculator_->StartCalculation()) {
1990 ResetProminentColors();
1991 }
1992 }
1993
ShouldCalculateColors() const1994 bool WallpaperControllerImpl::ShouldCalculateColors() const {
1995 gfx::ImageSkia image = GetWallpaper();
1996 return Shell::Get()->session_controller()->GetSessionState() ==
1997 session_manager::SessionState::ACTIVE &&
1998 !image.isNull();
1999 }
2000
CacheProminentColors(const std::vector<SkColor> & colors,const std::string & current_location)2001 void WallpaperControllerImpl::CacheProminentColors(
2002 const std::vector<SkColor>& colors,
2003 const std::string& current_location) {
2004 if (!local_state_)
2005 return;
2006 DictionaryPrefUpdate wallpaper_colors_update(local_state_,
2007 prefs::kWallpaperColors);
2008 auto wallpaper_colors = std::make_unique<base::ListValue>();
2009 for (SkColor color : colors)
2010 wallpaper_colors->AppendDouble(static_cast<double>(color));
2011 wallpaper_colors_update->SetWithoutPathExpansion(current_location,
2012 std::move(wallpaper_colors));
2013 }
2014
GetCachedColors(const std::string & current_location) const2015 base::Optional<std::vector<SkColor>> WallpaperControllerImpl::GetCachedColors(
2016 const std::string& current_location) const {
2017 base::Optional<std::vector<SkColor>> cached_colors_out;
2018 const base::ListValue* prominent_colors = nullptr;
2019 if (!local_state_ ||
2020 !local_state_->GetDictionary(prefs::kWallpaperColors)
2021 ->GetListWithoutPathExpansion(current_location, &prominent_colors)) {
2022 return cached_colors_out;
2023 }
2024 cached_colors_out = std::vector<SkColor>();
2025 cached_colors_out.value().reserve(prominent_colors->GetList().size());
2026 for (const auto& value : *prominent_colors) {
2027 cached_colors_out.value().push_back(
2028 static_cast<SkColor>(value.GetDouble()));
2029 }
2030 return cached_colors_out;
2031 }
2032
OnAlwaysOnTopWallpaperDecoded(const WallpaperInfo & info,const gfx::ImageSkia & image)2033 void WallpaperControllerImpl::OnAlwaysOnTopWallpaperDecoded(
2034 const WallpaperInfo& info,
2035 const gfx::ImageSkia& image) {
2036 // Do nothing if |RemoveAlwaysOnTopWallpaper| was called before decoding
2037 // completes.
2038 if (!is_always_on_top_wallpaper_)
2039 return;
2040 if (image.isNull()) {
2041 is_always_on_top_wallpaper_ = false;
2042 return;
2043 }
2044 reload_always_on_top_wallpaper_callback_ =
2045 base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage,
2046 weak_factory_.GetWeakPtr(), image, info,
2047 /*preview_mode=*/false, /*always_on_top=*/true);
2048 reload_always_on_top_wallpaper_callback_.Run();
2049 }
2050
IsDevicePolicyWallpaper() const2051 bool WallpaperControllerImpl::IsDevicePolicyWallpaper() const {
2052 return current_wallpaper_ &&
2053 current_wallpaper_->wallpaper_info().type == WallpaperType::DEVICE;
2054 }
2055
IsOneShotWallpaper() const2056 bool WallpaperControllerImpl::IsOneShotWallpaper() const {
2057 return current_wallpaper_ &&
2058 current_wallpaper_->wallpaper_info().type == WallpaperType::ONE_SHOT;
2059 }
2060
ShouldSetDevicePolicyWallpaper() const2061 bool WallpaperControllerImpl::ShouldSetDevicePolicyWallpaper() const {
2062 // Only allow the device wallpaper if the policy is in effect for enterprise
2063 // managed devices.
2064 if (device_policy_wallpaper_path_.empty())
2065 return false;
2066
2067 // Only set the device wallpaper if we're at the login screen.
2068 return Shell::Get()->session_controller()->GetSessionState() ==
2069 session_manager::SessionState::LOGIN_PRIMARY;
2070 }
2071
SetDevicePolicyWallpaper()2072 void WallpaperControllerImpl::SetDevicePolicyWallpaper() {
2073 DCHECK(ShouldSetDevicePolicyWallpaper());
2074 ReadAndDecodeWallpaper(
2075 base::BindOnce(&WallpaperControllerImpl::OnDevicePolicyWallpaperDecoded,
2076 weak_factory_.GetWeakPtr()),
2077 sequenced_task_runner_.get(), device_policy_wallpaper_path_);
2078 }
2079
OnDevicePolicyWallpaperDecoded(const gfx::ImageSkia & image)2080 void WallpaperControllerImpl::OnDevicePolicyWallpaperDecoded(
2081 const gfx::ImageSkia& image) {
2082 // It might be possible that the device policy controlled wallpaper finishes
2083 // decoding after the user logs in. In this case do nothing.
2084 if (!ShouldSetDevicePolicyWallpaper())
2085 return;
2086
2087 if (image.isNull()) {
2088 // If device policy wallpaper failed decoding, fall back to the default
2089 // wallpaper.
2090 SetDefaultWallpaperImpl(EmptyAccountId(), /*show_wallpaper=*/true);
2091 } else {
2092 WallpaperInfo info(device_policy_wallpaper_path_.value(),
2093 WALLPAPER_LAYOUT_CENTER_CROPPED, DEVICE,
2094 base::Time::Now().LocalMidnight());
2095 ShowWallpaperImage(image, info, /*preview_mode=*/false,
2096 /*always_on_top=*/false);
2097 }
2098 }
2099
GetInternalDisplayCompositorLock()2100 void WallpaperControllerImpl::GetInternalDisplayCompositorLock() {
2101 if (!display::Display::HasInternalDisplay())
2102 return;
2103
2104 aura::Window* root_window =
2105 Shell::GetRootWindowForDisplayId(display::Display::InternalDisplayId());
2106 if (!root_window)
2107 return;
2108
2109 compositor_lock_ = root_window->layer()->GetCompositor()->GetCompositorLock(
2110 this, kCompositorLockTimeout);
2111 }
2112
RepaintWallpaper()2113 void WallpaperControllerImpl::RepaintWallpaper() {
2114 for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
2115 auto* wallpaper_view =
2116 root_window_controller->wallpaper_widget_controller()->wallpaper_view();
2117 if (wallpaper_view)
2118 wallpaper_view->SchedulePaint();
2119 }
2120 }
2121
2122 } // namespace ash
2123