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