• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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 "chrome/browser/chromeos/login/wallpaper_manager.h"
6 
7 #include <vector>
8 
9 #include "ash/shell.h"
10 #include "base/command_line.h"
11 #include "base/debug/trace_event.h"
12 #include "base/file_util.h"
13 #include "base/files/file_enumerator.h"
14 #include "base/files/file_path.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram.h"
17 #include "base/path_service.h"
18 #include "base/prefs/pref_registry_simple.h"
19 #include "base/prefs/pref_service.h"
20 #include "base/prefs/scoped_user_pref_update.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/threading/worker_pool.h"
25 #include "base/time/time.h"
26 #include "base/values.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/chrome_notification_types.h"
29 #include "chrome/browser/chromeos/login/startup_utils.h"
30 #include "chrome/browser/chromeos/login/user.h"
31 #include "chrome/browser/chromeos/login/user_manager.h"
32 #include "chrome/browser/chromeos/login/wizard_controller.h"
33 #include "chrome/browser/chromeos/settings/cros_settings.h"
34 #include "chrome/common/chrome_paths.h"
35 #include "chrome/common/chrome_switches.h"
36 #include "chrome/common/pref_names.h"
37 #include "chromeos/chromeos_switches.h"
38 #include "chromeos/dbus/dbus_thread_manager.h"
39 #include "content/public/browser/browser_thread.h"
40 #include "content/public/browser/notification_service.h"
41 #include "ui/base/resource/resource_bundle.h"
42 #include "ui/gfx/codec/jpeg_codec.h"
43 #include "ui/gfx/image/image_skia_operations.h"
44 #include "ui/gfx/skia_util.h"
45 
46 using content::BrowserThread;
47 
48 namespace {
49 
50 // The amount of delay before starts to move custom wallpapers to the new place.
51 const int kMoveCustomWallpaperDelaySeconds = 30;
52 
53 // Default quality for encoding wallpaper.
54 const int kDefaultEncodingQuality = 90;
55 
56 // A dictionary pref that maps usernames to file paths to their wallpapers.
57 // Deprecated. Will remove this const char after done migration.
58 const char kUserWallpapers[] = "UserWallpapers";
59 
60 const int kCacheWallpaperDelayMs = 500;
61 
62 // A dictionary pref that maps usernames to wallpaper properties.
63 const char kUserWallpapersProperties[] = "UserWallpapersProperties";
64 
65 // Names of nodes with info about wallpaper in |kUserWallpapersProperties|
66 // dictionary.
67 const char kNewWallpaperDateNodeName[] = "date";
68 const char kNewWallpaperLayoutNodeName[] = "layout";
69 const char kNewWallpaperFileNodeName[] = "file";
70 const char kNewWallpaperTypeNodeName[] = "type";
71 
72 // File path suffix of the original custom wallpaper.
73 const char kOriginalCustomWallpaperSuffix[] = "_wallpaper";
74 
75 // Maximum number of wallpapers cached by CacheUsersWallpapers().
76 const int kMaxWallpapersToCache = 3;
77 
78 // For our scaling ratios we need to round positive numbers.
RoundPositive(double x)79 int RoundPositive(double x) {
80   return static_cast<int>(floor(x + 0.5));
81 }
82 
83 // Returns custom wallpaper directory by appending corresponding |sub_dir|.
GetCustomWallpaperDir(const char * sub_dir)84 base::FilePath GetCustomWallpaperDir(const char* sub_dir) {
85   base::FilePath custom_wallpaper_dir;
86   CHECK(PathService::Get(chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS,
87                          &custom_wallpaper_dir));
88   return custom_wallpaper_dir.Append(sub_dir);
89 }
90 
MoveCustomWallpaperDirectory(const char * sub_dir,const std::string & email,const std::string & user_id_hash)91 bool MoveCustomWallpaperDirectory(const char* sub_dir,
92                                   const std::string& email,
93                                   const std::string& user_id_hash) {
94   base::FilePath base_path = GetCustomWallpaperDir(sub_dir);
95   base::FilePath to_path = base_path.Append(user_id_hash);
96   base::FilePath from_path = base_path.Append(email);
97   if (base::PathExists(from_path))
98     return base::Move(from_path, to_path);
99   return false;
100 }
101 
102 }  // namespace
103 
104 namespace chromeos {
105 
106 const char kWallpaperSequenceTokenName[] = "wallpaper-sequence";
107 
108 const char kSmallWallpaperSuffix[] = "_small";
109 const char kLargeWallpaperSuffix[] = "_large";
110 
111 const char kSmallWallpaperSubDir[] = "small";
112 const char kLargeWallpaperSubDir[] = "large";
113 const char kOriginalWallpaperSubDir[] = "original";
114 const char kThumbnailWallpaperSubDir[] = "thumb";
115 
116 static WallpaperManager* g_wallpaper_manager = NULL;
117 
118 // WallpaperManager, public: ---------------------------------------------------
119 
120 // TestApi. For testing purpose
TestApi(WallpaperManager * wallpaper_manager)121 WallpaperManager::TestApi::TestApi(WallpaperManager* wallpaper_manager)
122     : wallpaper_manager_(wallpaper_manager) {
123 }
124 
~TestApi()125 WallpaperManager::TestApi::~TestApi() {
126 }
127 
current_wallpaper_path()128 base::FilePath WallpaperManager::TestApi::current_wallpaper_path() {
129   return wallpaper_manager_->current_wallpaper_path_;
130 }
131 
132 // static
Get()133 WallpaperManager* WallpaperManager::Get() {
134   if (!g_wallpaper_manager)
135     g_wallpaper_manager = new WallpaperManager();
136   return g_wallpaper_manager;
137 }
138 
WallpaperManager()139 WallpaperManager::WallpaperManager()
140     : loaded_wallpapers_(0),
141       command_line_for_testing_(NULL),
142       should_cache_wallpaper_(false),
143       weak_factory_(this) {
144   registrar_.Add(this,
145                  chrome::NOTIFICATION_LOGIN_USER_CHANGED,
146                  content::NotificationService::AllSources());
147   registrar_.Add(this,
148                  chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
149                  content::NotificationService::AllSources());
150   registrar_.Add(this,
151                  chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
152                  content::NotificationService::AllSources());
153   sequence_token_ = BrowserThread::GetBlockingPool()->
154       GetNamedSequenceToken(kWallpaperSequenceTokenName);
155   task_runner_ = BrowserThread::GetBlockingPool()->
156       GetSequencedTaskRunnerWithShutdownBehavior(
157           sequence_token_,
158           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
159   wallpaper_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
160                                           task_runner_);
161 }
162 
~WallpaperManager()163 WallpaperManager::~WallpaperManager() {
164   // TODO(bshe): Lifetime of WallpaperManager needs more consideration.
165   // http://crbug.com/171694
166   DCHECK(!show_user_name_on_signin_subscription_);
167   ClearObsoleteWallpaperPrefs();
168   weak_factory_.InvalidateWeakPtrs();
169 }
170 
Shutdown()171 void WallpaperManager::Shutdown() {
172   show_user_name_on_signin_subscription_.reset();
173 }
174 
175 // static
RegisterPrefs(PrefRegistrySimple * registry)176 void WallpaperManager::RegisterPrefs(PrefRegistrySimple* registry) {
177   registry->RegisterDictionaryPref(prefs::kUsersWallpaperInfo);
178   registry->RegisterDictionaryPref(kUserWallpapers);
179   registry->RegisterDictionaryPref(kUserWallpapersProperties);
180 }
181 
AddObservers()182 void WallpaperManager::AddObservers() {
183   show_user_name_on_signin_subscription_ =
184       CrosSettings::Get()->AddSettingsObserver(
185           kAccountsPrefShowUserNamesOnSignIn,
186           base::Bind(&WallpaperManager::InitializeRegisteredDeviceWallpaper,
187                      base::Unretained(this)));
188 }
189 
EnsureLoggedInUserWallpaperLoaded()190 void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() {
191   // Some browser tests do not have a shell instance. As no wallpaper is needed
192   // in these tests anyway, avoid loading one, preventing crashes and speeding
193   // up the tests.
194   if (!ash::Shell::HasInstance())
195     return;
196 
197   WallpaperInfo info;
198   if (GetLoggedInUserWallpaperInfo(&info)) {
199     // TODO(sschmitz): We need an index for default wallpapers for the new UI.
200     RecordUma(info.type, -1);
201     if (info == current_user_wallpaper_info_)
202       return;
203   }
204   SetUserWallpaper(UserManager::Get()->GetLoggedInUser()->email());
205 }
206 
ClearWallpaperCache()207 void WallpaperManager::ClearWallpaperCache() {
208   // Cancel callback for previous cache requests.
209   weak_factory_.InvalidateWeakPtrs();
210   wallpaper_cache_.clear();
211 }
212 
GetCustomWallpaperPath(const char * sub_dir,const std::string & user_id_hash,const std::string & file)213 base::FilePath WallpaperManager::GetCustomWallpaperPath(
214     const char* sub_dir,
215     const std::string& user_id_hash,
216     const std::string& file) {
217   base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
218   return custom_wallpaper_path.Append(user_id_hash).Append(file);
219 }
220 
GetWallpaperFromCache(const std::string & email,gfx::ImageSkia * wallpaper)221 bool WallpaperManager::GetWallpaperFromCache(const std::string& email,
222                                              gfx::ImageSkia* wallpaper) {
223   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224   CustomWallpaperMap::const_iterator it = wallpaper_cache_.find(email);
225   if (it != wallpaper_cache_.end()) {
226     *wallpaper = (*it).second;
227     return true;
228   }
229   return false;
230 }
231 
GetOriginalWallpaperPathForUser(const std::string & username)232 base::FilePath WallpaperManager::GetOriginalWallpaperPathForUser(
233     const std::string& username) {
234   std::string filename = username + kOriginalCustomWallpaperSuffix;
235   base::FilePath user_data_dir;
236   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
237   return user_data_dir.AppendASCII(filename);
238 }
239 
GetLoggedInUserWallpaperInfo(WallpaperInfo * info)240 bool WallpaperManager::GetLoggedInUserWallpaperInfo(WallpaperInfo* info) {
241   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
242 
243   if (UserManager::Get()->IsLoggedInAsStub()) {
244     info->file = current_user_wallpaper_info_.file = "";
245     info->layout = current_user_wallpaper_info_.layout =
246         ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
247     info->type = current_user_wallpaper_info_.type = User::DEFAULT;
248     return true;
249   }
250 
251   return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser()->email(),
252                               info);
253 }
254 
InitializeWallpaper()255 void WallpaperManager::InitializeWallpaper() {
256   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257   UserManager* user_manager = UserManager::Get();
258 
259   CommandLine* command_line = GetComandLine();
260   if (command_line->HasSwitch(chromeos::switches::kGuestSession)) {
261     // Guest wallpaper should be initialized when guest login.
262     // Note: This maybe called before login. So IsLoggedInAsGuest can not be
263     // used here to determine if current user is guest.
264     return;
265   }
266 
267   if (command_line->HasSwitch(::switches::kTestType))
268     WizardController::SetZeroDelays();
269 
270   // Zero delays is also set in autotests.
271   if (WizardController::IsZeroDelayEnabled()) {
272     // Ensure tests have some sort of wallpaper.
273     ash::Shell::GetInstance()->desktop_background_controller()->
274         CreateEmptyWallpaper();
275     return;
276   }
277 
278   if (!user_manager->IsUserLoggedIn()) {
279     if (!StartupUtils::IsDeviceRegistered())
280       SetDefaultWallpaper();
281     else
282       InitializeRegisteredDeviceWallpaper();
283     return;
284   }
285   SetUserWallpaper(user_manager->GetLoggedInUser()->email());
286 }
287 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)288 void WallpaperManager::Observe(int type,
289                                const content::NotificationSource& source,
290                                const content::NotificationDetails& details) {
291   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
292   switch (type) {
293     case chrome::NOTIFICATION_LOGIN_USER_CHANGED: {
294       ClearWallpaperCache();
295       BrowserThread::PostDelayedTask(
296           BrowserThread::UI,
297           FROM_HERE,
298           base::Bind(&WallpaperManager::MoveLoggedInUserCustomWallpaper,
299                      weak_factory_.GetWeakPtr()),
300           base::TimeDelta::FromSeconds(kMoveCustomWallpaperDelaySeconds));
301       break;
302     }
303     case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
304       if (!GetComandLine()->HasSwitch(switches::kDisableBootAnimation)) {
305         BrowserThread::PostDelayedTask(
306             BrowserThread::UI, FROM_HERE,
307             base::Bind(&WallpaperManager::CacheUsersWallpapers,
308                        weak_factory_.GetWeakPtr()),
309             base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
310       } else {
311         should_cache_wallpaper_ = true;
312       }
313       break;
314     }
315     case chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED: {
316       NotifyAnimationFinished();
317       if (should_cache_wallpaper_) {
318         BrowserThread::PostDelayedTask(
319             BrowserThread::UI, FROM_HERE,
320             base::Bind(&WallpaperManager::CacheUsersWallpapers,
321                        weak_factory_.GetWeakPtr()),
322             base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
323         should_cache_wallpaper_ = false;
324       }
325       break;
326     }
327     default:
328       NOTREACHED() << "Unexpected notification " << type;
329   }
330 }
331 
RemoveUserWallpaperInfo(const std::string & email)332 void WallpaperManager::RemoveUserWallpaperInfo(const std::string& email) {
333   WallpaperInfo info;
334   GetUserWallpaperInfo(email, &info);
335   PrefService* prefs = g_browser_process->local_state();
336   DictionaryPrefUpdate prefs_wallpapers_info_update(prefs,
337       prefs::kUsersWallpaperInfo);
338   prefs_wallpapers_info_update->RemoveWithoutPathExpansion(email, NULL);
339   DeleteUserWallpapers(email, info.file);
340 }
341 
ResizeWallpaper(const UserImage & wallpaper,ash::WallpaperLayout layout,int preferred_width,int preferred_height,scoped_refptr<base::RefCountedBytes> * output)342 bool WallpaperManager::ResizeWallpaper(
343     const UserImage& wallpaper,
344     ash::WallpaperLayout layout,
345     int preferred_width,
346     int preferred_height,
347     scoped_refptr<base::RefCountedBytes>* output) {
348   DCHECK(BrowserThread::GetBlockingPool()->
349       IsRunningSequenceOnCurrentThread(sequence_token_));
350   int width = wallpaper.image().width();
351   int height = wallpaper.image().height();
352   int resized_width;
353   int resized_height;
354   *output = new base::RefCountedBytes();
355 
356   if (layout == ash::WALLPAPER_LAYOUT_CENTER_CROPPED) {
357     // Do not resize custom wallpaper if it is smaller than preferred size.
358     if (!(width > preferred_width && height > preferred_height))
359       return false;
360 
361     double horizontal_ratio = static_cast<double>(preferred_width) / width;
362     double vertical_ratio = static_cast<double>(preferred_height) / height;
363     if (vertical_ratio > horizontal_ratio) {
364       resized_width =
365           RoundPositive(static_cast<double>(width) * vertical_ratio);
366       resized_height = preferred_height;
367     } else {
368       resized_width = preferred_width;
369       resized_height =
370           RoundPositive(static_cast<double>(height) * horizontal_ratio);
371     }
372   } else if (layout == ash::WALLPAPER_LAYOUT_STRETCH) {
373     resized_width = preferred_width;
374     resized_height = preferred_height;
375   } else {
376     resized_width = width;
377     resized_height = height;
378   }
379 
380   gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage(
381       wallpaper.image(),
382       skia::ImageOperations::RESIZE_LANCZOS3,
383       gfx::Size(resized_width, resized_height));
384 
385   SkBitmap image = *(resized_image.bitmap());
386   SkAutoLockPixels lock_input(image);
387   gfx::JPEGCodec::Encode(
388       reinterpret_cast<unsigned char*>(image.getAddr32(0, 0)),
389       gfx::JPEGCodec::FORMAT_SkBitmap,
390       image.width(),
391       image.height(),
392       image.width() * image.bytesPerPixel(),
393       kDefaultEncodingQuality, &(*output)->data());
394   return true;
395 }
396 
ResizeAndSaveWallpaper(const UserImage & wallpaper,const base::FilePath & path,ash::WallpaperLayout layout,int preferred_width,int preferred_height)397 void WallpaperManager::ResizeAndSaveWallpaper(const UserImage& wallpaper,
398                                               const base::FilePath& path,
399                                               ash::WallpaperLayout layout,
400                                               int preferred_width,
401                                               int preferred_height) {
402   if (layout == ash::WALLPAPER_LAYOUT_CENTER) {
403     // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
404     if (base::PathExists(path))
405       base::DeleteFile(path, false);
406     return;
407   }
408   scoped_refptr<base::RefCountedBytes> data;
409   if (ResizeWallpaper(wallpaper, layout, preferred_width, preferred_height,
410                       &data)) {
411     SaveWallpaperInternal(path,
412                           reinterpret_cast<const char*>(data->front()),
413                           data->size());
414   }
415 }
416 
SetCustomWallpaper(const std::string & username,const std::string & user_id_hash,const std::string & file,ash::WallpaperLayout layout,User::WallpaperType type,const UserImage & wallpaper)417 void WallpaperManager::SetCustomWallpaper(const std::string& username,
418                                           const std::string& user_id_hash,
419                                           const std::string& file,
420                                           ash::WallpaperLayout layout,
421                                           User::WallpaperType type,
422                                           const UserImage& wallpaper) {
423   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
424 
425   base::FilePath wallpaper_path =
426       GetCustomWallpaperPath(kOriginalWallpaperSubDir, user_id_hash, file);
427 
428   // If decoded wallpaper is empty, we are probably failed to decode the file.
429   // Use default wallpaper in this case.
430   if (wallpaper.image().isNull()) {
431     SetDefaultWallpaper();
432     return;
433   }
434 
435   bool is_persistent =
436       !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(username);
437 
438   wallpaper.image().EnsureRepsForSupportedScales();
439   scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper.image().DeepCopy());
440 
441   WallpaperInfo wallpaper_info = {
442       wallpaper_path.value(),
443       layout,
444       type,
445       // Date field is not used.
446       base::Time::Now().LocalMidnight()
447   };
448   // Block shutdown on this task. Otherwise, we may lost the custom wallpaper
449   // user selected.
450   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
451       BrowserThread::GetBlockingPool()->
452           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
453               base::SequencedWorkerPool::BLOCK_SHUTDOWN);
454   // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
455   blocking_task_runner->PostTask(FROM_HERE,
456       base::Bind(&WallpaperManager::ProcessCustomWallpaper,
457                  base::Unretained(this),
458                  user_id_hash,
459                  is_persistent,
460                  wallpaper_info,
461                  base::Passed(&deep_copy),
462                  wallpaper.raw_image()));
463   ash::Shell::GetInstance()->desktop_background_controller()->
464       SetCustomWallpaper(wallpaper.image(), layout);
465 
466   std::string relative_path = base::FilePath(user_id_hash).Append(file).value();
467   // User's custom wallpaper path is determined by relative path and the
468   // appropriate wallpaper resolution in GetCustomWallpaperInternal.
469   WallpaperInfo info = {
470       relative_path,
471       layout,
472       User::CUSTOMIZED,
473       base::Time::Now().LocalMidnight()
474   };
475   SetUserWallpaperInfo(username, info, is_persistent);
476 }
477 
SetDefaultWallpaper()478 void WallpaperManager::SetDefaultWallpaper() {
479   current_wallpaper_path_.clear();
480   if (ash::Shell::GetInstance()->desktop_background_controller()->
481           SetDefaultWallpaper(UserManager::Get()->IsLoggedInAsGuest()))
482     loaded_wallpapers_++;
483 }
484 
SetInitialUserWallpaper(const std::string & username,bool is_persistent)485 void WallpaperManager::SetInitialUserWallpaper(const std::string& username,
486                                                bool is_persistent) {
487   current_user_wallpaper_info_.file = "";
488   current_user_wallpaper_info_.layout = ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
489   current_user_wallpaper_info_.type = User::DEFAULT;
490   current_user_wallpaper_info_.date = base::Time::Now().LocalMidnight();
491 
492   WallpaperInfo info = current_user_wallpaper_info_;
493   SetUserWallpaperInfo(username, info, is_persistent);
494   SetLastSelectedUser(username);
495 
496   // Some browser tests do not have a shell instance. As no wallpaper is needed
497   // in these tests anyway, avoid loading one, preventing crashes and speeding
498   // up the tests.
499   if (ash::Shell::HasInstance())
500     SetDefaultWallpaper();
501 }
502 
SetUserWallpaperInfo(const std::string & username,const WallpaperInfo & info,bool is_persistent)503 void WallpaperManager::SetUserWallpaperInfo(const std::string& username,
504                                             const WallpaperInfo& info,
505                                             bool is_persistent) {
506   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507   current_user_wallpaper_info_ = info;
508   if (!is_persistent)
509     return;
510 
511   PrefService* local_state = g_browser_process->local_state();
512   DictionaryPrefUpdate wallpaper_update(local_state,
513                                         prefs::kUsersWallpaperInfo);
514 
515   base::DictionaryValue* wallpaper_info_dict = new base::DictionaryValue();
516   wallpaper_info_dict->SetString(kNewWallpaperDateNodeName,
517       base::Int64ToString(info.date.ToInternalValue()));
518   wallpaper_info_dict->SetString(kNewWallpaperFileNodeName, info.file);
519   wallpaper_info_dict->SetInteger(kNewWallpaperLayoutNodeName, info.layout);
520   wallpaper_info_dict->SetInteger(kNewWallpaperTypeNodeName, info.type);
521   wallpaper_update->SetWithoutPathExpansion(username, wallpaper_info_dict);
522 }
523 
SetLastSelectedUser(const std::string & last_selected_user)524 void WallpaperManager::SetLastSelectedUser(
525     const std::string& last_selected_user) {
526   last_selected_user_ = last_selected_user;
527 }
528 
SetUserWallpaper(const std::string & email)529 void WallpaperManager::SetUserWallpaper(const std::string& email) {
530   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
531   if (email == UserManager::kGuestUserName) {
532     SetDefaultWallpaper();
533     return;
534   }
535 
536   if (!UserManager::Get()->IsKnownUser(email))
537     return;
538 
539   SetLastSelectedUser(email);
540 
541   WallpaperInfo info;
542 
543   if (GetUserWallpaperInfo(email, &info)) {
544     gfx::ImageSkia user_wallpaper;
545     current_user_wallpaper_info_ = info;
546     if (GetWallpaperFromCache(email, &user_wallpaper)) {
547       ash::Shell::GetInstance()->desktop_background_controller()->
548           SetCustomWallpaper(user_wallpaper, info.layout);
549     } else {
550       if (info.type == User::CUSTOMIZED) {
551         ash::WallpaperResolution resolution = ash::Shell::GetInstance()->
552             desktop_background_controller()->GetAppropriateResolution();
553         const char* sub_dir = (resolution == ash::WALLPAPER_RESOLUTION_SMALL) ?
554             kSmallWallpaperSubDir : kLargeWallpaperSubDir;
555         // Wallpaper is not resized when layout is ash::WALLPAPER_LAYOUT_CENTER.
556         // Original wallpaper should be used in this case.
557         // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
558         if (info.layout == ash::WALLPAPER_LAYOUT_CENTER)
559           sub_dir = kOriginalWallpaperSubDir;
560         base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
561         wallpaper_path = wallpaper_path.Append(info.file);
562         if (current_wallpaper_path_ == wallpaper_path)
563           return;
564         current_wallpaper_path_ = wallpaper_path;
565         loaded_wallpapers_++;
566 
567         task_runner_->PostTask(FROM_HERE,
568             base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
569                        base::Unretained(this), email, info, wallpaper_path,
570                        true /* update wallpaper */));
571         return;
572       }
573 
574       if (info.file.empty()) {
575         // Uses default built-in wallpaper when file is empty. Eventually, we
576         // will only ship one built-in wallpaper in ChromeOS image.
577         SetDefaultWallpaper();
578         return;
579       }
580 
581       // Load downloaded ONLINE or converted DEFAULT wallpapers.
582       LoadWallpaper(email, info, true /* update wallpaper */);
583     }
584   } else {
585     SetInitialUserWallpaper(email, true);
586   }
587 }
588 
SetWallpaperFromImageSkia(const gfx::ImageSkia & wallpaper,ash::WallpaperLayout layout)589 void WallpaperManager::SetWallpaperFromImageSkia(
590     const gfx::ImageSkia& wallpaper,
591     ash::WallpaperLayout layout) {
592   ash::Shell::GetInstance()->desktop_background_controller()->
593       SetCustomWallpaper(wallpaper, layout);
594 }
595 
UpdateWallpaper()596 void WallpaperManager::UpdateWallpaper() {
597   ClearWallpaperCache();
598   current_wallpaper_path_.clear();
599   // For GAIA login flow, the last_selected_user_ may not be set before user
600   // login. If UpdateWallpaper is called at GAIA login screen, no wallpaper will
601   // be set. It could result a black screen on external monitors.
602   // See http://crbug.com/265689 for detail.
603   if (last_selected_user_.empty()) {
604     SetDefaultWallpaper();
605     return;
606   }
607   SetUserWallpaper(last_selected_user_);
608 }
609 
AddObserver(WallpaperManager::Observer * observer)610 void WallpaperManager::AddObserver(WallpaperManager::Observer* observer) {
611   observers_.AddObserver(observer);
612 }
613 
RemoveObserver(WallpaperManager::Observer * observer)614 void WallpaperManager::RemoveObserver(WallpaperManager::Observer* observer) {
615   observers_.RemoveObserver(observer);
616 }
617 
NotifyAnimationFinished()618 void WallpaperManager::NotifyAnimationFinished() {
619   FOR_EACH_OBSERVER(
620       Observer, observers_, OnWallpaperAnimationFinished(last_selected_user_));
621 }
622 
623 // WallpaperManager, private: --------------------------------------------------
624 
CacheUsersWallpapers()625 void WallpaperManager::CacheUsersWallpapers() {
626   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
627   UserList users = UserManager::Get()->GetUsers();
628 
629   if (!users.empty()) {
630     UserList::const_iterator it = users.begin();
631     // Skip the wallpaper of first user in the list. It should have been cached.
632     it++;
633     for (int cached = 0;
634          it != users.end() && cached < kMaxWallpapersToCache;
635          ++it, ++cached) {
636       std::string user_email = (*it)->email();
637       CacheUserWallpaper(user_email);
638     }
639   }
640 }
641 
CacheUserWallpaper(const std::string & email)642 void WallpaperManager::CacheUserWallpaper(const std::string& email) {
643   if (wallpaper_cache_.find(email) == wallpaper_cache_.end())
644     return;
645   WallpaperInfo info;
646   if (GetUserWallpaperInfo(email, &info)) {
647     base::FilePath wallpaper_dir;
648     base::FilePath wallpaper_path;
649     if (info.type == User::CUSTOMIZED) {
650       ash::WallpaperResolution resolution = ash::Shell::GetInstance()->
651           desktop_background_controller()->GetAppropriateResolution();
652       const char* sub_dir  = (resolution == ash::WALLPAPER_RESOLUTION_SMALL) ?
653             kSmallWallpaperSubDir : kLargeWallpaperSubDir;
654       base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
655       wallpaper_path = wallpaper_path.Append(info.file);
656       task_runner_->PostTask(FROM_HERE,
657           base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
658                      base::Unretained(this), email, info, wallpaper_path,
659                      false /* do not update wallpaper */));
660       return;
661     }
662     LoadWallpaper(email, info, false /* do not update wallpaper */);
663   }
664 }
665 
ClearObsoleteWallpaperPrefs()666 void WallpaperManager::ClearObsoleteWallpaperPrefs() {
667   PrefService* prefs = g_browser_process->local_state();
668   DictionaryPrefUpdate wallpaper_properties_pref(prefs,
669       kUserWallpapersProperties);
670   wallpaper_properties_pref->Clear();
671   DictionaryPrefUpdate wallpapers_pref(prefs, kUserWallpapers);
672   wallpapers_pref->Clear();
673 }
674 
DeleteAllExcept(const base::FilePath & path)675 void WallpaperManager::DeleteAllExcept(const base::FilePath& path) {
676   base::FilePath dir = path.DirName();
677   if (base::DirectoryExists(dir)) {
678     base::FileEnumerator files(dir, false, base::FileEnumerator::FILES);
679     for (base::FilePath current = files.Next(); !current.empty();
680          current = files.Next()) {
681       if (current != path)
682         base::DeleteFile(current, false);
683     }
684   }
685 }
686 
DeleteWallpaperInList(const std::vector<base::FilePath> & file_list)687 void WallpaperManager::DeleteWallpaperInList(
688     const std::vector<base::FilePath>& file_list) {
689   for (std::vector<base::FilePath>::const_iterator it = file_list.begin();
690        it != file_list.end(); ++it) {
691     base::FilePath path = *it;
692     // Some users may still have legacy wallpapers with png extension. We need
693     // to delete these wallpapers too.
694     if (!base::DeleteFile(path, true) &&
695         !base::DeleteFile(path.AddExtension(".png"), false)) {
696       LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
697     }
698   }
699 }
700 
DeleteUserWallpapers(const std::string & email,const std::string & path_to_file)701 void WallpaperManager::DeleteUserWallpapers(const std::string& email,
702                                             const std::string& path_to_file) {
703   std::vector<base::FilePath> file_to_remove;
704   // Remove small user wallpaper.
705   base::FilePath wallpaper_path =
706       GetCustomWallpaperDir(kSmallWallpaperSubDir);
707   // Remove old directory if exists
708   file_to_remove.push_back(wallpaper_path.Append(email));
709   wallpaper_path = wallpaper_path.Append(path_to_file).DirName();
710   file_to_remove.push_back(wallpaper_path);
711 
712   // Remove large user wallpaper.
713   wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
714   file_to_remove.push_back(wallpaper_path.Append(email));
715   wallpaper_path = wallpaper_path.Append(path_to_file);
716   file_to_remove.push_back(wallpaper_path);
717 
718   // Remove user wallpaper thumbnail.
719   wallpaper_path = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
720   file_to_remove.push_back(wallpaper_path.Append(email));
721   wallpaper_path = wallpaper_path.Append(path_to_file);
722   file_to_remove.push_back(wallpaper_path);
723 
724   // Remove original user wallpaper.
725   wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
726   file_to_remove.push_back(wallpaper_path.Append(email));
727   wallpaper_path = wallpaper_path.Append(path_to_file);
728   file_to_remove.push_back(wallpaper_path);
729 
730   base::WorkerPool::PostTask(
731       FROM_HERE,
732       base::Bind(&WallpaperManager::DeleteWallpaperInList,
733                  base::Unretained(this),
734                  file_to_remove),
735       false);
736 }
737 
EnsureCustomWallpaperDirectories(const std::string & user_id_hash)738 void WallpaperManager::EnsureCustomWallpaperDirectories(
739     const std::string& user_id_hash) {
740   base::FilePath dir;
741   dir = GetCustomWallpaperDir(kSmallWallpaperSubDir);
742   dir = dir.Append(user_id_hash);
743   if (!base::PathExists(dir))
744     base::CreateDirectory(dir);
745   dir = GetCustomWallpaperDir(kLargeWallpaperSubDir);
746   dir = dir.Append(user_id_hash);
747   if (!base::PathExists(dir))
748     base::CreateDirectory(dir);
749   dir = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
750   dir = dir.Append(user_id_hash);
751   if (!base::PathExists(dir))
752     base::CreateDirectory(dir);
753   dir = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
754   dir = dir.Append(user_id_hash);
755   if (!base::PathExists(dir))
756     base::CreateDirectory(dir);
757 }
758 
GetComandLine()759 CommandLine* WallpaperManager::GetComandLine() {
760   CommandLine* command_line = command_line_for_testing_ ?
761       command_line_for_testing_ : CommandLine::ForCurrentProcess();
762   return command_line;
763 }
764 
InitializeRegisteredDeviceWallpaper()765 void WallpaperManager::InitializeRegisteredDeviceWallpaper() {
766   if (UserManager::Get()->IsUserLoggedIn())
767     return;
768 
769   bool disable_boot_animation = GetComandLine()->
770       HasSwitch(switches::kDisableBootAnimation);
771   bool show_users = true;
772   bool result = CrosSettings::Get()->GetBoolean(
773       kAccountsPrefShowUserNamesOnSignIn, &show_users);
774   DCHECK(result) << "Unable to fetch setting "
775                  << kAccountsPrefShowUserNamesOnSignIn;
776   const chromeos::UserList& users = UserManager::Get()->GetUsers();
777   if (!show_users || users.empty()) {
778     // Boot into sign in form, preload default wallpaper.
779     SetDefaultWallpaper();
780     return;
781   }
782 
783   if (!disable_boot_animation) {
784     // Normal boot, load user wallpaper.
785     // If normal boot animation is disabled wallpaper would be set
786     // asynchronously once user pods are loaded.
787     SetUserWallpaper(users[0]->email());
788   }
789 }
790 
LoadWallpaper(const std::string & email,const WallpaperInfo & info,bool update_wallpaper)791 void WallpaperManager::LoadWallpaper(const std::string& email,
792                                      const WallpaperInfo& info,
793                                      bool update_wallpaper) {
794   base::FilePath wallpaper_dir;
795   base::FilePath wallpaper_path;
796   if (info.type == User::ONLINE) {
797     std::string file_name = GURL(info.file).ExtractFileName();
798     ash::WallpaperResolution resolution = ash::Shell::GetInstance()->
799         desktop_background_controller()->GetAppropriateResolution();
800     // Only solid color wallpapers have stretch layout and they have only one
801     // resolution.
802     if (info.layout != ash::WALLPAPER_LAYOUT_STRETCH &&
803         resolution == ash::WALLPAPER_RESOLUTION_SMALL) {
804       file_name = base::FilePath(file_name).InsertBeforeExtension(
805           kSmallWallpaperSuffix).value();
806     }
807     CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
808     wallpaper_path = wallpaper_dir.Append(file_name);
809     if (current_wallpaper_path_ == wallpaper_path)
810       return;
811     if (update_wallpaper)
812       current_wallpaper_path_ = wallpaper_path;
813     loaded_wallpapers_++;
814     StartLoad(email, info, update_wallpaper, wallpaper_path);
815   } else if (info.type == User::DEFAULT) {
816     // Default wallpapers are migrated from M21 user profiles. A code refactor
817     // overlooked that case and caused these wallpapers not being loaded at all.
818     // On some slow devices, it caused login webui not visible after upgrade to
819     // M26 from M21. See crosbug.com/38429 for details.
820     base::FilePath user_data_dir;
821     PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
822     wallpaper_path = user_data_dir.Append(info.file);
823     StartLoad(email, info, update_wallpaper, wallpaper_path);
824   } else {
825     // In unexpected cases, revert to default wallpaper to fail safely. See
826     // crosbug.com/38429.
827     LOG(ERROR) << "Wallpaper reverts to default unexpected.";
828     SetDefaultWallpaper();
829   }
830 }
831 
GetUserWallpaperInfo(const std::string & email,WallpaperInfo * info)832 bool WallpaperManager::GetUserWallpaperInfo(const std::string& email,
833                                             WallpaperInfo* info){
834   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
835 
836   if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(email)) {
837     // Default to the values cached in memory.
838     *info = current_user_wallpaper_info_;
839 
840     // Ephemeral users do not save anything to local state. But we have got
841     // wallpaper info from memory. Returns true.
842     return true;
843   }
844 
845   const DictionaryValue* user_wallpapers = g_browser_process->local_state()->
846       GetDictionary(prefs::kUsersWallpaperInfo);
847   const base::DictionaryValue* wallpaper_info_dict;
848   if (user_wallpapers->GetDictionaryWithoutPathExpansion(
849           email, &wallpaper_info_dict)) {
850     info->file = "";
851     info->layout = ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
852     info->type = User::UNKNOWN;
853     info->date = base::Time::Now().LocalMidnight();
854     wallpaper_info_dict->GetString(kNewWallpaperFileNodeName, &(info->file));
855     int temp;
856     wallpaper_info_dict->GetInteger(kNewWallpaperLayoutNodeName, &temp);
857     info->layout = static_cast<ash::WallpaperLayout>(temp);
858     wallpaper_info_dict->GetInteger(kNewWallpaperTypeNodeName, &temp);
859     info->type = static_cast<User::WallpaperType>(temp);
860     std::string date_string;
861     int64 val;
862     if (!(wallpaper_info_dict->GetString(kNewWallpaperDateNodeName,
863                                          &date_string) &&
864           base::StringToInt64(date_string, &val)))
865       val = 0;
866     info->date = base::Time::FromInternalValue(val);
867     return true;
868   }
869 
870   return false;
871 }
872 
MoveCustomWallpapersOnWorker(const std::string & email,const std::string & user_id_hash)873 void WallpaperManager::MoveCustomWallpapersOnWorker(
874     const std::string& email,
875     const std::string& user_id_hash) {
876   DCHECK(BrowserThread::GetBlockingPool()->
877       IsRunningSequenceOnCurrentThread(sequence_token_));
878   if (MoveCustomWallpaperDirectory(kOriginalWallpaperSubDir,
879                                    email,
880                                    user_id_hash)) {
881     // Consider success if the original wallpaper is moved to the new directory.
882     // Original wallpaper is the fallback if the correct resolution wallpaper
883     // can not be found.
884     BrowserThread::PostTask(
885         BrowserThread::UI, FROM_HERE,
886         base::Bind(&WallpaperManager::MoveCustomWallpapersSuccess,
887                    base::Unretained(this),
888                    email,
889                    user_id_hash));
890   }
891   MoveCustomWallpaperDirectory(kLargeWallpaperSubDir, email, user_id_hash);
892   MoveCustomWallpaperDirectory(kSmallWallpaperSubDir, email, user_id_hash);
893   MoveCustomWallpaperDirectory(kThumbnailWallpaperSubDir, email, user_id_hash);
894 }
895 
MoveCustomWallpapersSuccess(const std::string & email,const std::string & user_id_hash)896 void WallpaperManager::MoveCustomWallpapersSuccess(
897     const std::string& email,
898     const std::string& user_id_hash) {
899   WallpaperInfo info;
900   GetUserWallpaperInfo(email, &info);
901   if (info.type == User::CUSTOMIZED) {
902     // New file field should include user id hash in addition to file name.
903     // This is needed because at login screen, user id hash is not available.
904     std::string relative_path =
905         base::FilePath(user_id_hash).Append(info.file).value();
906     info.file = relative_path;
907     bool is_persistent =
908         !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(email);
909     SetUserWallpaperInfo(email, info, is_persistent);
910   }
911 }
912 
MoveLoggedInUserCustomWallpaper()913 void WallpaperManager::MoveLoggedInUserCustomWallpaper() {
914   const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
915   task_runner_->PostTask(
916       FROM_HERE,
917       base::Bind(&WallpaperManager::MoveCustomWallpapersOnWorker,
918                  base::Unretained(this),
919                  logged_in_user->email(),
920                  logged_in_user->username_hash()));
921 }
922 
GetCustomWallpaperInternal(const std::string & email,const WallpaperInfo & info,const base::FilePath & wallpaper_path,bool update_wallpaper)923 void WallpaperManager::GetCustomWallpaperInternal(
924     const std::string& email,
925     const WallpaperInfo& info,
926     const base::FilePath& wallpaper_path,
927     bool update_wallpaper) {
928   DCHECK(BrowserThread::GetBlockingPool()->
929       IsRunningSequenceOnCurrentThread(sequence_token_));
930 
931   base::FilePath valid_path = wallpaper_path;
932   if (!base::PathExists(wallpaper_path)) {
933     // Falls back on original file if the correct resoltuion file does not
934     // exist. This may happen when the original custom wallpaper is small or
935     // browser shutdown before resized wallpaper saved.
936     valid_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
937     valid_path = valid_path.Append(info.file);
938   }
939 
940   if (!base::PathExists(valid_path)) {
941     // Falls back to custom wallpaper that uses email as part of its file path.
942     // Note that email is used instead of user_id_hash here.
943     valid_path = GetCustomWallpaperPath(kOriginalWallpaperSubDir, email,
944                                         info.file);
945   }
946 
947   if (!base::PathExists(valid_path)) {
948     LOG(ERROR) << "Failed to load previously selected custom wallpaper. " <<
949                   "Fallback to default wallpaper";
950     BrowserThread::PostTask(BrowserThread::UI,
951                             FROM_HERE,
952                             base::Bind(&WallpaperManager::SetDefaultWallpaper,
953                                        base::Unretained(this)));
954   } else {
955     BrowserThread::PostTask(BrowserThread::UI,
956                             FROM_HERE,
957                             base::Bind(&WallpaperManager::StartLoad,
958                                        base::Unretained(this),
959                                        email,
960                                        info,
961                                        update_wallpaper,
962                                        valid_path));
963   }
964 }
965 
OnWallpaperDecoded(const std::string & email,ash::WallpaperLayout layout,bool update_wallpaper,const UserImage & wallpaper)966 void WallpaperManager::OnWallpaperDecoded(const std::string& email,
967                                           ash::WallpaperLayout layout,
968                                           bool update_wallpaper,
969                                           const UserImage& wallpaper) {
970   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
971   TRACE_EVENT_ASYNC_END0("ui", "LoadAndDecodeWallpaper", this);
972 
973   // If decoded wallpaper is empty, we are probably failed to decode the file.
974   // Use default wallpaper in this case.
975   if (wallpaper.image().isNull()) {
976     // Updates user pref to default wallpaper.
977     WallpaperInfo info = {
978                            "",
979                            ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
980                            User::DEFAULT,
981                            base::Time::Now().LocalMidnight()
982                          };
983     SetUserWallpaperInfo(email, info, true);
984 
985     if (update_wallpaper)
986       SetDefaultWallpaper();
987     return;
988   }
989 
990   // Only cache user wallpaper at login screen.
991   if (!UserManager::Get()->IsUserLoggedIn()) {
992     wallpaper_cache_.insert(std::make_pair(email, wallpaper.image()));
993   }
994   if (update_wallpaper) {
995     ash::Shell::GetInstance()->desktop_background_controller()->
996         SetCustomWallpaper(wallpaper.image(), layout);
997   }
998 }
999 
ProcessCustomWallpaper(const std::string & user_id_hash,bool persistent,const WallpaperInfo & info,scoped_ptr<gfx::ImageSkia> image,const UserImage::RawImage & raw_image)1000 void WallpaperManager::ProcessCustomWallpaper(
1001     const std::string& user_id_hash,
1002     bool persistent,
1003     const WallpaperInfo& info,
1004     scoped_ptr<gfx::ImageSkia> image,
1005     const UserImage::RawImage& raw_image) {
1006   DCHECK(BrowserThread::GetBlockingPool()->
1007       IsRunningSequenceOnCurrentThread(sequence_token_));
1008   UserImage wallpaper(*image.get(), raw_image);
1009   if (persistent) {
1010     SaveCustomWallpaper(user_id_hash, base::FilePath(info.file), info.layout,
1011                         wallpaper);
1012   }
1013 }
1014 
SaveCustomWallpaper(const std::string & user_id_hash,const base::FilePath & original_path,ash::WallpaperLayout layout,const UserImage & wallpaper)1015 void WallpaperManager::SaveCustomWallpaper(const std::string& user_id_hash,
1016                                            const base::FilePath& original_path,
1017                                            ash::WallpaperLayout layout,
1018                                            const UserImage& wallpaper) {
1019   DCHECK(BrowserThread::GetBlockingPool()->
1020       IsRunningSequenceOnCurrentThread(sequence_token_));
1021   EnsureCustomWallpaperDirectories(user_id_hash);
1022   std::string file_name = original_path.BaseName().value();
1023   base::FilePath small_wallpaper_path =
1024       GetCustomWallpaperPath(kSmallWallpaperSubDir, user_id_hash, file_name);
1025   base::FilePath large_wallpaper_path =
1026       GetCustomWallpaperPath(kLargeWallpaperSubDir, user_id_hash, file_name);
1027 
1028   // Re-encode orginal file to jpeg format and saves the result in case that
1029   // resized wallpaper is not generated (i.e. chrome shutdown before resized
1030   // wallpaper is saved).
1031   ResizeAndSaveWallpaper(wallpaper, original_path,
1032                          ash::WALLPAPER_LAYOUT_STRETCH,
1033                          wallpaper.image().width(),
1034                          wallpaper.image().height());
1035   DeleteAllExcept(original_path);
1036 
1037   ResizeAndSaveWallpaper(wallpaper, small_wallpaper_path, layout,
1038                          ash::kSmallWallpaperMaxWidth,
1039                          ash::kSmallWallpaperMaxHeight);
1040   DeleteAllExcept(small_wallpaper_path);
1041   ResizeAndSaveWallpaper(wallpaper, large_wallpaper_path, layout,
1042                          ash::kLargeWallpaperMaxWidth,
1043                          ash::kLargeWallpaperMaxHeight);
1044   DeleteAllExcept(large_wallpaper_path);
1045 }
1046 
RecordUma(User::WallpaperType type,int index)1047 void WallpaperManager::RecordUma(User::WallpaperType type, int index) {
1048   UMA_HISTOGRAM_ENUMERATION("Ash.Wallpaper.Type", type,
1049                             User::WALLPAPER_TYPE_COUNT);
1050 }
1051 
SaveWallpaperInternal(const base::FilePath & path,const char * data,int size)1052 void WallpaperManager::SaveWallpaperInternal(const base::FilePath& path,
1053                                              const char* data,
1054                                              int size) {
1055   int written_bytes = file_util::WriteFile(path, data, size);
1056   DCHECK(written_bytes == size);
1057 }
1058 
StartLoad(const std::string & email,const WallpaperInfo & info,bool update_wallpaper,const base::FilePath & wallpaper_path)1059 void WallpaperManager::StartLoad(const std::string& email,
1060                                  const WallpaperInfo& info,
1061                                  bool update_wallpaper,
1062                                  const base::FilePath& wallpaper_path) {
1063   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1064   TRACE_EVENT_ASYNC_BEGIN0("ui", "LoadAndDecodeWallpaper", this);
1065 
1066   wallpaper_loader_->Start(wallpaper_path.value(), 0,
1067                            base::Bind(&WallpaperManager::OnWallpaperDecoded,
1068                                       base::Unretained(this),
1069                                       email,
1070                                       info.layout,
1071                                       update_wallpaper));
1072 }
1073 
1074 }  // namespace chromeos
1075