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