Home | History | Annotate | Download | only in extensions
      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/extensions/wallpaper_private_api.h"
      6 
      7 #include <vector>
      8 
      9 #include "ash/ash_switches.h"
     10 #include "ash/desktop_background/desktop_background_controller.h"
     11 #include "ash/shell.h"
     12 #include "ash/wm/mru_window_tracker.h"
     13 #include "ash/wm/window_state.h"
     14 #include "ash/wm/window_util.h"
     15 #include "base/command_line.h"
     16 #include "base/files/file_enumerator.h"
     17 #include "base/files/file_util.h"
     18 #include "base/memory/scoped_ptr.h"
     19 #include "base/path_service.h"
     20 #include "base/prefs/pref_service.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "base/strings/stringprintf.h"
     23 #include "base/threading/worker_pool.h"
     24 #include "chrome/browser/browser_process.h"
     25 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
     26 #include "chrome/browser/profiles/profile.h"
     27 #include "chrome/common/chrome_paths.h"
     28 #include "chrome/common/pref_names.h"
     29 #include "chrome/grit/generated_resources.h"
     30 #include "components/user_manager/user.h"
     31 #include "components/user_manager/user_manager.h"
     32 #include "content/public/browser/browser_thread.h"
     33 #include "extensions/browser/event_router.h"
     34 #include "grit/components_strings.h"
     35 #include "ui/base/l10n/l10n_util.h"
     36 #include "ui/base/webui/web_ui_util.h"
     37 #include "ui/strings/grit/app_locale_settings.h"
     38 #include "url/gurl.h"
     39 
     40 using base::BinaryValue;
     41 using content::BrowserThread;
     42 namespace wallpaper_private = extensions::api::wallpaper_private;
     43 namespace set_wallpaper_if_exists = wallpaper_private::SetWallpaperIfExists;
     44 namespace set_wallpaper = wallpaper_private::SetWallpaper;
     45 namespace set_custom_wallpaper = wallpaper_private::SetCustomWallpaper;
     46 namespace set_custom_wallpaper_layout =
     47     wallpaper_private::SetCustomWallpaperLayout;
     48 namespace get_thumbnail = wallpaper_private::GetThumbnail;
     49 namespace save_thumbnail = wallpaper_private::SaveThumbnail;
     50 namespace get_offline_wallpaper_list =
     51     wallpaper_private::GetOfflineWallpaperList;
     52 
     53 namespace {
     54 
     55 #if defined(GOOGLE_CHROME_BUILD)
     56 const char kWallpaperManifestBaseURL[] =
     57     "https://storage.googleapis.com/chromeos-wallpaper-public/manifest_";
     58 #endif
     59 
     60 bool IsOEMDefaultWallpaper() {
     61   return CommandLine::ForCurrentProcess()->HasSwitch(
     62       ash::switches::kAshDefaultWallpaperIsOem);
     63 }
     64 
     65 // Saves |data| as |file_name| to directory with |key|. Return false if the
     66 // directory can not be found/created or failed to write file.
     67 bool SaveData(int key, const std::string& file_name, const std::string& data) {
     68   base::FilePath data_dir;
     69   CHECK(PathService::Get(key, &data_dir));
     70   if (!base::DirectoryExists(data_dir) &&
     71       !base::CreateDirectory(data_dir)) {
     72     return false;
     73   }
     74   base::FilePath file_path = data_dir.Append(file_name);
     75 
     76   return base::PathExists(file_path) ||
     77          (base::WriteFile(file_path, data.c_str(), data.size()) != -1);
     78 }
     79 
     80 // Gets |file_name| from directory with |key|. Return false if the directory can
     81 // not be found or failed to read file to string |data|. Note if the |file_name|
     82 // can not be found in the directory, return true with empty |data|. It is
     83 // expected that we may try to access file which did not saved yet.
     84 bool GetData(const base::FilePath& path, std::string* data) {
     85   base::FilePath data_dir = path.DirName();
     86   if (!base::DirectoryExists(data_dir) &&
     87       !base::CreateDirectory(data_dir))
     88     return false;
     89 
     90   return !base::PathExists(path) ||
     91          base::ReadFileToString(path, data);
     92 }
     93 
     94 // WindowStateManager remembers which windows have been minimized in order to
     95 // restore them when the wallpaper viewer is hidden.
     96 class WindowStateManager : public aura::WindowObserver {
     97  public:
     98   typedef std::map<std::string, std::set<aura::Window*> >
     99       UserIDHashWindowListMap;
    100 
    101   // Minimizes all windows except the active window.
    102   static void MinimizeInactiveWindows(const std::string& user_id_hash);
    103 
    104   // Unminimizes all minimized windows restoring them to their previous state.
    105   // This should only be called after calling MinimizeInactiveWindows.
    106   static void RestoreWindows(const std::string& user_id_hash);
    107 
    108  private:
    109   WindowStateManager();
    110 
    111   virtual ~WindowStateManager();
    112 
    113   // Store all unminimized windows except |active_window| and minimize them.
    114   // All the windows are saved in a map and the key value is |user_id_hash|.
    115   void BuildWindowListAndMinimizeInactiveForUser(
    116       const std::string& user_id_hash, aura::Window* active_window);
    117 
    118   // Unminimize all the stored windows for |user_id_hash|.
    119   void RestoreMinimizedWindows(const std::string& user_id_hash);
    120 
    121   // Remove the observer from |window| if |window| is no longer referenced in
    122   // user_id_hash_window_list_map_.
    123   void RemoveObserverIfUnreferenced(aura::Window* window);
    124 
    125   // aura::WindowObserver overrides.
    126   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
    127 
    128   // Map of user id hash and associated list of minimized windows.
    129   UserIDHashWindowListMap user_id_hash_window_list_map_;
    130 
    131   DISALLOW_COPY_AND_ASSIGN(WindowStateManager);
    132 };
    133 
    134 // static
    135 WindowStateManager* g_window_state_manager = NULL;
    136 
    137 // static
    138 void WindowStateManager::MinimizeInactiveWindows(
    139     const std::string& user_id_hash) {
    140   if (!g_window_state_manager)
    141     g_window_state_manager = new WindowStateManager();
    142   g_window_state_manager->BuildWindowListAndMinimizeInactiveForUser(
    143       user_id_hash, ash::wm::GetActiveWindow());
    144 }
    145 
    146 // static
    147 void WindowStateManager::RestoreWindows(const std::string& user_id_hash) {
    148   if (!g_window_state_manager) {
    149     DCHECK(false) << "This should only be called after calling "
    150                   << "MinimizeInactiveWindows.";
    151     return;
    152   }
    153 
    154   g_window_state_manager->RestoreMinimizedWindows(user_id_hash);
    155   if (g_window_state_manager->user_id_hash_window_list_map_.empty()) {
    156     delete g_window_state_manager;
    157     g_window_state_manager = NULL;
    158   }
    159 }
    160 
    161 WindowStateManager::WindowStateManager() {}
    162 
    163 WindowStateManager::~WindowStateManager() {}
    164 
    165 void WindowStateManager::BuildWindowListAndMinimizeInactiveForUser(
    166     const std::string& user_id_hash, aura::Window* active_window) {
    167   if (user_id_hash_window_list_map_.find(user_id_hash) ==
    168       user_id_hash_window_list_map_.end()) {
    169     user_id_hash_window_list_map_[user_id_hash] = std::set<aura::Window*>();
    170   }
    171   std::set<aura::Window*>* results =
    172       &user_id_hash_window_list_map_[user_id_hash];
    173 
    174   std::vector<aura::Window*> windows =
    175       ash::MruWindowTracker::BuildWindowList(false);
    176 
    177   for (std::vector<aura::Window*>::iterator iter = windows.begin();
    178        iter != windows.end(); ++iter) {
    179     // Ignore active window and minimized windows.
    180     if (*iter == active_window || ash::wm::GetWindowState(*iter)->IsMinimized())
    181       continue;
    182 
    183     // TODO(bshe): Add WindowStateObserver too. http://crbug.com/323252
    184     if (!(*iter)->HasObserver(this))
    185       (*iter)->AddObserver(this);
    186 
    187     results->insert(*iter);
    188     ash::wm::GetWindowState(*iter)->Minimize();
    189   }
    190 }
    191 
    192 void WindowStateManager::RestoreMinimizedWindows(
    193     const std::string& user_id_hash) {
    194   UserIDHashWindowListMap::iterator it =
    195       user_id_hash_window_list_map_.find(user_id_hash);
    196   if (it == user_id_hash_window_list_map_.end()) {
    197     DCHECK(false) << "This should only be called after calling "
    198                   << "MinimizeInactiveWindows.";
    199     return;
    200   }
    201 
    202   std::set<aura::Window*> removed_windows;
    203   removed_windows.swap(it->second);
    204   user_id_hash_window_list_map_.erase(it);
    205 
    206   for (std::set<aura::Window*>::iterator iter = removed_windows.begin();
    207        iter != removed_windows.end(); ++iter) {
    208     ash::wm::GetWindowState(*iter)->Unminimize();
    209     RemoveObserverIfUnreferenced(*iter);
    210   }
    211 }
    212 
    213 void WindowStateManager::RemoveObserverIfUnreferenced(aura::Window* window) {
    214   for (UserIDHashWindowListMap::iterator iter =
    215            user_id_hash_window_list_map_.begin();
    216        iter != user_id_hash_window_list_map_.end();
    217        ++iter) {
    218     if (iter->second.find(window) != iter->second.end())
    219       return;
    220   }
    221   // Remove observer if |window| is not observed by any users.
    222   window->RemoveObserver(this);
    223 }
    224 
    225 void WindowStateManager::OnWindowDestroyed(aura::Window* window) {
    226   for (UserIDHashWindowListMap::iterator iter =
    227            user_id_hash_window_list_map_.begin();
    228        iter != user_id_hash_window_list_map_.end();
    229        ++iter) {
    230     iter->second.erase(window);
    231   }
    232 }
    233 
    234 }  // namespace
    235 
    236 bool WallpaperPrivateGetStringsFunction::RunSync() {
    237   base::DictionaryValue* dict = new base::DictionaryValue();
    238   SetResult(dict);
    239 
    240 #define SET_STRING(id, idr) \
    241   dict->SetString(id, l10n_util::GetStringUTF16(idr))
    242   SET_STRING("webFontFamily", IDS_WEB_FONT_FAMILY);
    243   SET_STRING("webFontSize", IDS_WEB_FONT_SIZE);
    244   SET_STRING("allCategoryLabel", IDS_WALLPAPER_MANAGER_ALL_CATEGORY_LABEL);
    245   SET_STRING("deleteCommandLabel", IDS_WALLPAPER_MANAGER_DELETE_COMMAND_LABEL);
    246   SET_STRING("customCategoryLabel",
    247              IDS_WALLPAPER_MANAGER_CUSTOM_CATEGORY_LABEL);
    248   SET_STRING("selectCustomLabel",
    249              IDS_WALLPAPER_MANAGER_SELECT_CUSTOM_LABEL);
    250   SET_STRING("positionLabel", IDS_WALLPAPER_MANAGER_POSITION_LABEL);
    251   SET_STRING("colorLabel", IDS_WALLPAPER_MANAGER_COLOR_LABEL);
    252   SET_STRING("centerCroppedLayout",
    253              IDS_OPTIONS_WALLPAPER_CENTER_CROPPED_LAYOUT);
    254   SET_STRING("centerLayout", IDS_OPTIONS_WALLPAPER_CENTER_LAYOUT);
    255   SET_STRING("stretchLayout", IDS_OPTIONS_WALLPAPER_STRETCH_LAYOUT);
    256   SET_STRING("connectionFailed", IDS_WALLPAPER_MANAGER_ACCESS_FAIL);
    257   SET_STRING("downloadFailed", IDS_WALLPAPER_MANAGER_DOWNLOAD_FAIL);
    258   SET_STRING("downloadCanceled", IDS_WALLPAPER_MANAGER_DOWNLOAD_CANCEL);
    259   SET_STRING("customWallpaperWarning",
    260              IDS_WALLPAPER_MANAGER_SHOW_CUSTOM_WALLPAPER_ON_START_WARNING);
    261   SET_STRING("accessFileFailure", IDS_WALLPAPER_MANAGER_ACCESS_FILE_FAILURE);
    262   SET_STRING("invalidWallpaper", IDS_WALLPAPER_MANAGER_INVALID_WALLPAPER);
    263   SET_STRING("surpriseMeLabel", IDS_WALLPAPER_MANAGER_SURPRISE_ME_LABEL);
    264   SET_STRING("learnMore", IDS_LEARN_MORE);
    265   SET_STRING("currentWallpaperSetByMessage",
    266              IDS_CURRENT_WALLPAPER_SET_BY_MESSAGE);
    267 #undef SET_STRING
    268 
    269   webui::SetFontAndTextDirection(dict);
    270 
    271   chromeos::WallpaperManager* wallpaper_manager =
    272       chromeos::WallpaperManager::Get();
    273   chromeos::WallpaperInfo info;
    274 
    275   if (wallpaper_manager->GetLoggedInUserWallpaperInfo(&info))
    276     dict->SetString("currentWallpaper", info.location);
    277 
    278 #if defined(GOOGLE_CHROME_BUILD)
    279   dict->SetString("manifestBaseURL", kWallpaperManifestBaseURL);
    280 #endif
    281 
    282   Profile* profile = Profile::FromBrowserContext(browser_context());
    283   std::string app_name(
    284       profile->GetPrefs()->GetString(prefs::kCurrentWallpaperAppName));
    285   if (!app_name.empty())
    286     dict->SetString("wallpaperAppName", app_name);
    287 
    288   dict->SetBoolean("isOEMDefaultWallpaper", IsOEMDefaultWallpaper());
    289   dict->SetString("canceledWallpaper",
    290                   wallpaper_api_util::kCancelWallpaperMessage);
    291   return true;
    292 }
    293 
    294 WallpaperPrivateSetWallpaperIfExistsFunction::
    295     WallpaperPrivateSetWallpaperIfExistsFunction() {}
    296 
    297 WallpaperPrivateSetWallpaperIfExistsFunction::
    298     ~WallpaperPrivateSetWallpaperIfExistsFunction() {}
    299 
    300 bool WallpaperPrivateSetWallpaperIfExistsFunction::RunAsync() {
    301 #if !defined(USE_ATHENA)
    302   // TODO(bshe): Support wallpaper manager in Athena, crbug.com/408734.
    303   params = set_wallpaper_if_exists::Params::Create(*args_);
    304   EXTENSION_FUNCTION_VALIDATE(params);
    305 
    306   user_id_ = user_manager::UserManager::Get()->GetActiveUser()->email();
    307 
    308   base::FilePath wallpaper_path;
    309   base::FilePath fallback_path;
    310   chromeos::WallpaperManager::WallpaperResolution resolution =
    311       chromeos::WallpaperManager::GetAppropriateResolution();
    312 
    313   std::string file_name = GURL(params->url).ExtractFileName();
    314   CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
    315                          &wallpaper_path));
    316   fallback_path = wallpaper_path.Append(file_name);
    317   if (params->layout != wallpaper_private::WALLPAPER_LAYOUT_STRETCH &&
    318       resolution == chromeos::WallpaperManager::WALLPAPER_RESOLUTION_SMALL) {
    319     file_name = base::FilePath(file_name).InsertBeforeExtension(
    320         chromeos::kSmallWallpaperSuffix).value();
    321   }
    322   wallpaper_path = wallpaper_path.Append(file_name);
    323 
    324   sequence_token_ = BrowserThread::GetBlockingPool()->
    325       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    326   scoped_refptr<base::SequencedTaskRunner> task_runner =
    327       BrowserThread::GetBlockingPool()->
    328           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    329               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
    330 
    331   task_runner->PostTask(FROM_HERE,
    332       base::Bind(
    333           &WallpaperPrivateSetWallpaperIfExistsFunction::
    334               ReadFileAndInitiateStartDecode,
    335           this, wallpaper_path, fallback_path));
    336 #endif
    337   return true;
    338 }
    339 
    340 void WallpaperPrivateSetWallpaperIfExistsFunction::
    341     ReadFileAndInitiateStartDecode(const base::FilePath& file_path,
    342                                    const base::FilePath& fallback_path) {
    343   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    344       sequence_token_));
    345   std::string data;
    346   base::FilePath path = file_path;
    347 
    348   if (!base::PathExists(file_path))
    349     path = fallback_path;
    350 
    351   if (base::PathExists(path) &&
    352       base::ReadFileToString(path, &data)) {
    353     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    354         base::Bind(&WallpaperPrivateSetWallpaperIfExistsFunction::StartDecode,
    355                    this, data));
    356     return;
    357   }
    358   std::string error = base::StringPrintf(
    359         "Failed to set wallpaper %s from file system.",
    360         path.BaseName().value().c_str());
    361   BrowserThread::PostTask(
    362       BrowserThread::UI, FROM_HERE,
    363       base::Bind(&WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists,
    364                  this, error));
    365 }
    366 
    367 void WallpaperPrivateSetWallpaperIfExistsFunction::OnWallpaperDecoded(
    368     const gfx::ImageSkia& image) {
    369   // Set unsafe_wallpaper_decoder_ to null since the decoding already finished.
    370   unsafe_wallpaper_decoder_ = NULL;
    371 
    372   chromeos::WallpaperManager* wallpaper_manager =
    373       chromeos::WallpaperManager::Get();
    374   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
    375       wallpaper_private::ToString(params->layout));
    376 
    377   bool update_wallpaper =
    378       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
    379   wallpaper_manager->SetWallpaperFromImageSkia(
    380       user_id_, image, layout, update_wallpaper);
    381   bool is_persistent = !user_manager::UserManager::Get()
    382                             ->IsCurrentUserNonCryptohomeDataEphemeral();
    383   chromeos::WallpaperInfo info = {params->url, layout,
    384                                   user_manager::User::ONLINE,
    385                                   base::Time::Now().LocalMidnight()};
    386   wallpaper_manager->SetUserWallpaperInfo(user_id_, info, is_persistent);
    387   SetResult(new base::FundamentalValue(true));
    388   Profile* profile = Profile::FromBrowserContext(browser_context());
    389   // This API is only available to the component wallpaper picker. We do not
    390   // need to show the app's name if it is the component wallpaper picker. So set
    391   // the pref to empty string.
    392   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
    393                                  std::string());
    394   SendResponse(true);
    395 }
    396 
    397 void WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists(
    398     const std::string& error) {
    399   SetResult(new base::FundamentalValue(false));
    400   OnFailure(error);
    401 }
    402 
    403 WallpaperPrivateSetWallpaperFunction::WallpaperPrivateSetWallpaperFunction() {
    404 }
    405 
    406 WallpaperPrivateSetWallpaperFunction::~WallpaperPrivateSetWallpaperFunction() {
    407 }
    408 
    409 bool WallpaperPrivateSetWallpaperFunction::RunAsync() {
    410   params = set_wallpaper::Params::Create(*args_);
    411   EXTENSION_FUNCTION_VALIDATE(params);
    412 
    413   // Gets email address while at UI thread.
    414   user_id_ = user_manager::UserManager::Get()->GetActiveUser()->email();
    415 
    416   StartDecode(params->wallpaper);
    417 
    418   return true;
    419 }
    420 
    421 void WallpaperPrivateSetWallpaperFunction::OnWallpaperDecoded(
    422     const gfx::ImageSkia& image) {
    423   wallpaper_ = image;
    424   // Set unsafe_wallpaper_decoder_ to null since the decoding already finished.
    425   unsafe_wallpaper_decoder_ = NULL;
    426 
    427   sequence_token_ = BrowserThread::GetBlockingPool()->
    428       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    429   scoped_refptr<base::SequencedTaskRunner> task_runner =
    430       BrowserThread::GetBlockingPool()->
    431           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    432               base::SequencedWorkerPool::BLOCK_SHUTDOWN);
    433 
    434   task_runner->PostTask(FROM_HERE,
    435       base::Bind(&WallpaperPrivateSetWallpaperFunction::SaveToFile, this));
    436 }
    437 
    438 void WallpaperPrivateSetWallpaperFunction::SaveToFile() {
    439   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    440       sequence_token_));
    441   std::string file_name = GURL(params->url).ExtractFileName();
    442   if (SaveData(chrome::DIR_CHROMEOS_WALLPAPERS, file_name, params->wallpaper)) {
    443     wallpaper_.EnsureRepsForSupportedScales();
    444     scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper_.DeepCopy());
    445     // ImageSkia is not RefCountedThreadSafe. Use a deep copied ImageSkia if
    446     // post to another thread.
    447     BrowserThread::PostTask(
    448         BrowserThread::UI,
    449         FROM_HERE,
    450         base::Bind(&WallpaperPrivateSetWallpaperFunction::SetDecodedWallpaper,
    451                    this,
    452                    base::Passed(deep_copy.Pass())));
    453 
    454     base::FilePath wallpaper_dir;
    455     CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
    456     base::FilePath file_path = wallpaper_dir.Append(
    457         file_name).InsertBeforeExtension(chromeos::kSmallWallpaperSuffix);
    458     if (base::PathExists(file_path))
    459       return;
    460     // Generates and saves small resolution wallpaper. Uses CENTER_CROPPED to
    461     // maintain the aspect ratio after resize.
    462     chromeos::WallpaperManager::Get()->ResizeAndSaveWallpaper(
    463         wallpaper_,
    464         file_path,
    465         ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
    466         chromeos::kSmallWallpaperMaxWidth,
    467         chromeos::kSmallWallpaperMaxHeight,
    468         NULL);
    469   } else {
    470     std::string error = base::StringPrintf(
    471         "Failed to create/write wallpaper to %s.", file_name.c_str());
    472     BrowserThread::PostTask(
    473         BrowserThread::UI, FROM_HERE,
    474         base::Bind(&WallpaperPrivateSetWallpaperFunction::OnFailure,
    475                    this, error));
    476   }
    477 }
    478 
    479 void WallpaperPrivateSetWallpaperFunction::SetDecodedWallpaper(
    480     scoped_ptr<gfx::ImageSkia> image) {
    481   chromeos::WallpaperManager* wallpaper_manager =
    482       chromeos::WallpaperManager::Get();
    483 
    484   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
    485       wallpaper_private::ToString(params->layout));
    486 
    487   bool update_wallpaper =
    488       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
    489   wallpaper_manager->SetWallpaperFromImageSkia(
    490       user_id_, *image.get(), layout, update_wallpaper);
    491 
    492   bool is_persistent = !user_manager::UserManager::Get()
    493                             ->IsCurrentUserNonCryptohomeDataEphemeral();
    494   chromeos::WallpaperInfo info = {params->url, layout,
    495                                   user_manager::User::ONLINE,
    496                                   base::Time::Now().LocalMidnight()};
    497   Profile* profile = Profile::FromBrowserContext(browser_context());
    498   // This API is only available to the component wallpaper picker. We do not
    499   // need to show the app's name if it is the component wallpaper picker. So set
    500   // the pref to empty string.
    501   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
    502                                  std::string());
    503   wallpaper_manager->SetUserWallpaperInfo(user_id_, info, is_persistent);
    504   SendResponse(true);
    505 }
    506 
    507 WallpaperPrivateResetWallpaperFunction::
    508     WallpaperPrivateResetWallpaperFunction() {}
    509 
    510 WallpaperPrivateResetWallpaperFunction::
    511     ~WallpaperPrivateResetWallpaperFunction() {}
    512 
    513 bool WallpaperPrivateResetWallpaperFunction::RunAsync() {
    514   chromeos::WallpaperManager* wallpaper_manager =
    515       chromeos::WallpaperManager::Get();
    516   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
    517 
    518   std::string user_id = user_manager->GetActiveUser()->email();
    519   wallpaper_manager->RemoveUserWallpaperInfo(user_id);
    520 
    521   chromeos::WallpaperInfo info = {std::string(),
    522                                   ash::WALLPAPER_LAYOUT_CENTER,
    523                                   user_manager::User::DEFAULT,
    524                                   base::Time::Now().LocalMidnight()};
    525   bool is_persistent =
    526       !user_manager->IsCurrentUserNonCryptohomeDataEphemeral();
    527   wallpaper_manager->SetUserWallpaperInfo(user_id, info, is_persistent);
    528 
    529   wallpaper_manager->SetDefaultWallpaperNow(user_id);
    530   Profile* profile = Profile::FromBrowserContext(browser_context());
    531   // This API is only available to the component wallpaper picker. We do not
    532   // need to show the app's name if it is the component wallpaper picker. So set
    533   // the pref to empty string.
    534   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
    535                                  std::string());
    536   return true;
    537 }
    538 
    539 WallpaperPrivateSetCustomWallpaperFunction::
    540     WallpaperPrivateSetCustomWallpaperFunction() {}
    541 
    542 WallpaperPrivateSetCustomWallpaperFunction::
    543     ~WallpaperPrivateSetCustomWallpaperFunction() {}
    544 
    545 bool WallpaperPrivateSetCustomWallpaperFunction::RunAsync() {
    546   params = set_custom_wallpaper::Params::Create(*args_);
    547   EXTENSION_FUNCTION_VALIDATE(params);
    548 
    549   // Gets email address and username hash while at UI thread.
    550   user_id_ = user_manager::UserManager::Get()->GetActiveUser()->email();
    551   user_id_hash_ =
    552       user_manager::UserManager::Get()->GetActiveUser()->username_hash();
    553 
    554   StartDecode(params->wallpaper);
    555 
    556   return true;
    557 }
    558 
    559 void WallpaperPrivateSetCustomWallpaperFunction::OnWallpaperDecoded(
    560     const gfx::ImageSkia& image) {
    561   chromeos::WallpaperManager* wallpaper_manager =
    562       chromeos::WallpaperManager::Get();
    563   base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath(
    564       chromeos::kThumbnailWallpaperSubDir, user_id_hash_, params->file_name);
    565 
    566   sequence_token_ = BrowserThread::GetBlockingPool()->
    567       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    568   scoped_refptr<base::SequencedTaskRunner> task_runner =
    569       BrowserThread::GetBlockingPool()->
    570           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    571               base::SequencedWorkerPool::BLOCK_SHUTDOWN);
    572 
    573   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
    574       wallpaper_private::ToString(params->layout));
    575 
    576   bool update_wallpaper =
    577       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
    578   wallpaper_manager->SetCustomWallpaper(user_id_,
    579                                         user_id_hash_,
    580                                         params->file_name,
    581                                         layout,
    582                                         user_manager::User::CUSTOMIZED,
    583                                         image,
    584                                         update_wallpaper);
    585   unsafe_wallpaper_decoder_ = NULL;
    586 
    587   Profile* profile = Profile::FromBrowserContext(browser_context());
    588   // This API is only available to the component wallpaper picker. We do not
    589   // need to show the app's name if it is the component wallpaper picker. So set
    590   // the pref to empty string.
    591   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
    592                                  std::string());
    593 
    594   if (params->generate_thumbnail) {
    595     image.EnsureRepsForSupportedScales();
    596     scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy());
    597     // Generates thumbnail before call api function callback. We can then
    598     // request thumbnail in the javascript callback.
    599     task_runner->PostTask(FROM_HERE,
    600         base::Bind(
    601             &WallpaperPrivateSetCustomWallpaperFunction::GenerateThumbnail,
    602             this, thumbnail_path, base::Passed(&deep_copy)));
    603   } else {
    604     SendResponse(true);
    605   }
    606 }
    607 
    608 void WallpaperPrivateSetCustomWallpaperFunction::GenerateThumbnail(
    609     const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
    610   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    611       sequence_token_));
    612   if (!base::PathExists(thumbnail_path.DirName()))
    613     base::CreateDirectory(thumbnail_path.DirName());
    614 
    615   scoped_refptr<base::RefCountedBytes> data;
    616   chromeos::WallpaperManager::Get()->ResizeImage(
    617       *image,
    618       ash::WALLPAPER_LAYOUT_STRETCH,
    619       chromeos::kWallpaperThumbnailWidth,
    620       chromeos::kWallpaperThumbnailHeight,
    621       &data,
    622       NULL);
    623   BrowserThread::PostTask(
    624         BrowserThread::UI, FROM_HERE,
    625         base::Bind(
    626             &WallpaperPrivateSetCustomWallpaperFunction::ThumbnailGenerated,
    627             this, data));
    628 }
    629 
    630 void WallpaperPrivateSetCustomWallpaperFunction::ThumbnailGenerated(
    631     base::RefCountedBytes* data) {
    632   BinaryValue* result = BinaryValue::CreateWithCopiedBuffer(
    633       reinterpret_cast<const char*>(data->front()), data->size());
    634   SetResult(result);
    635   SendResponse(true);
    636 }
    637 
    638 WallpaperPrivateSetCustomWallpaperLayoutFunction::
    639     WallpaperPrivateSetCustomWallpaperLayoutFunction() {}
    640 
    641 WallpaperPrivateSetCustomWallpaperLayoutFunction::
    642     ~WallpaperPrivateSetCustomWallpaperLayoutFunction() {}
    643 
    644 bool WallpaperPrivateSetCustomWallpaperLayoutFunction::RunAsync() {
    645   scoped_ptr<set_custom_wallpaper_layout::Params> params(
    646       set_custom_wallpaper_layout::Params::Create(*args_));
    647   EXTENSION_FUNCTION_VALIDATE(params);
    648 
    649   chromeos::WallpaperManager* wallpaper_manager =
    650       chromeos::WallpaperManager::Get();
    651   chromeos::WallpaperInfo info;
    652   wallpaper_manager->GetLoggedInUserWallpaperInfo(&info);
    653   if (info.type != user_manager::User::CUSTOMIZED) {
    654     SetError("Only custom wallpaper can change layout.");
    655     SendResponse(false);
    656     return false;
    657   }
    658   info.layout = wallpaper_api_util::GetLayoutEnum(
    659       wallpaper_private::ToString(params->layout));
    660 
    661   std::string email =
    662       user_manager::UserManager::Get()->GetActiveUser()->email();
    663   bool is_persistent = !user_manager::UserManager::Get()
    664                             ->IsCurrentUserNonCryptohomeDataEphemeral();
    665   wallpaper_manager->SetUserWallpaperInfo(email, info, is_persistent);
    666   wallpaper_manager->UpdateWallpaper(false /* clear_cache */);
    667   SendResponse(true);
    668 
    669   // Gets email address while at UI thread.
    670   return true;
    671 }
    672 
    673 WallpaperPrivateMinimizeInactiveWindowsFunction::
    674     WallpaperPrivateMinimizeInactiveWindowsFunction() {
    675 }
    676 
    677 WallpaperPrivateMinimizeInactiveWindowsFunction::
    678     ~WallpaperPrivateMinimizeInactiveWindowsFunction() {
    679 }
    680 
    681 bool WallpaperPrivateMinimizeInactiveWindowsFunction::RunAsync() {
    682   WindowStateManager::MinimizeInactiveWindows(
    683       user_manager::UserManager::Get()->GetActiveUser()->username_hash());
    684   return true;
    685 }
    686 
    687 WallpaperPrivateRestoreMinimizedWindowsFunction::
    688     WallpaperPrivateRestoreMinimizedWindowsFunction() {
    689 }
    690 
    691 WallpaperPrivateRestoreMinimizedWindowsFunction::
    692     ~WallpaperPrivateRestoreMinimizedWindowsFunction() {
    693 }
    694 
    695 bool WallpaperPrivateRestoreMinimizedWindowsFunction::RunAsync() {
    696   WindowStateManager::RestoreWindows(
    697       user_manager::UserManager::Get()->GetActiveUser()->username_hash());
    698   return true;
    699 }
    700 
    701 WallpaperPrivateGetThumbnailFunction::WallpaperPrivateGetThumbnailFunction() {
    702 }
    703 
    704 WallpaperPrivateGetThumbnailFunction::~WallpaperPrivateGetThumbnailFunction() {
    705 }
    706 
    707 bool WallpaperPrivateGetThumbnailFunction::RunAsync() {
    708   scoped_ptr<get_thumbnail::Params> params(
    709       get_thumbnail::Params::Create(*args_));
    710   EXTENSION_FUNCTION_VALIDATE(params);
    711 
    712   base::FilePath thumbnail_path;
    713   std::string email =
    714       user_manager::UserManager::Get()->GetActiveUser()->email();
    715   if (params->source == get_thumbnail::Params::SOURCE_ONLINE) {
    716     std::string file_name = GURL(params->url_or_file).ExtractFileName();
    717     CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS,
    718                            &thumbnail_path));
    719     thumbnail_path = thumbnail_path.Append(file_name);
    720   } else {
    721     if (!IsOEMDefaultWallpaper()) {
    722       SetError("No OEM wallpaper.");
    723       SendResponse(false);
    724       return false;
    725     }
    726 
    727     // TODO(bshe): Small resolution wallpaper is used here as wallpaper
    728     // thumbnail. We should either resize it or include a wallpaper thumbnail in
    729     // addition to large and small wallpaper resolutions.
    730     thumbnail_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    731         ash::switches::kAshDefaultWallpaperSmall);
    732   }
    733 
    734   sequence_token_ = BrowserThread::GetBlockingPool()->
    735       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    736   scoped_refptr<base::SequencedTaskRunner> task_runner =
    737       BrowserThread::GetBlockingPool()->
    738           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    739               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
    740 
    741   task_runner->PostTask(FROM_HERE,
    742       base::Bind(&WallpaperPrivateGetThumbnailFunction::Get, this,
    743                  thumbnail_path));
    744   return true;
    745 }
    746 
    747 void WallpaperPrivateGetThumbnailFunction::Failure(
    748     const std::string& file_name) {
    749   SetError(base::StringPrintf("Failed to access wallpaper thumbnails for %s.",
    750                               file_name.c_str()));
    751   SendResponse(false);
    752 }
    753 
    754 void WallpaperPrivateGetThumbnailFunction::FileNotLoaded() {
    755   SendResponse(true);
    756 }
    757 
    758 void WallpaperPrivateGetThumbnailFunction::FileLoaded(
    759     const std::string& data) {
    760   BinaryValue* thumbnail = BinaryValue::CreateWithCopiedBuffer(data.c_str(),
    761                                                                data.size());
    762   SetResult(thumbnail);
    763   SendResponse(true);
    764 }
    765 
    766 void WallpaperPrivateGetThumbnailFunction::Get(const base::FilePath& path) {
    767   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    768       sequence_token_));
    769   std::string data;
    770   if (GetData(path, &data)) {
    771     if (data.empty()) {
    772       BrowserThread::PostTask(
    773         BrowserThread::UI, FROM_HERE,
    774         base::Bind(&WallpaperPrivateGetThumbnailFunction::FileNotLoaded, this));
    775     } else {
    776       BrowserThread::PostTask(
    777         BrowserThread::UI, FROM_HERE,
    778         base::Bind(&WallpaperPrivateGetThumbnailFunction::FileLoaded, this,
    779                    data));
    780     }
    781   } else {
    782     BrowserThread::PostTask(
    783         BrowserThread::UI, FROM_HERE,
    784         base::Bind(&WallpaperPrivateGetThumbnailFunction::Failure, this,
    785                    path.BaseName().value()));
    786   }
    787 }
    788 
    789 WallpaperPrivateSaveThumbnailFunction::WallpaperPrivateSaveThumbnailFunction() {
    790 }
    791 
    792 WallpaperPrivateSaveThumbnailFunction::
    793     ~WallpaperPrivateSaveThumbnailFunction() {}
    794 
    795 bool WallpaperPrivateSaveThumbnailFunction::RunAsync() {
    796   scoped_ptr<save_thumbnail::Params> params(
    797       save_thumbnail::Params::Create(*args_));
    798   EXTENSION_FUNCTION_VALIDATE(params);
    799 
    800   sequence_token_ = BrowserThread::GetBlockingPool()->
    801       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    802   scoped_refptr<base::SequencedTaskRunner> task_runner =
    803       BrowserThread::GetBlockingPool()->
    804           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    805               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
    806 
    807   task_runner->PostTask(FROM_HERE,
    808       base::Bind(&WallpaperPrivateSaveThumbnailFunction::Save,
    809                  this, params->data, GURL(params->url).ExtractFileName()));
    810   return true;
    811 }
    812 
    813 void WallpaperPrivateSaveThumbnailFunction::Failure(
    814     const std::string& file_name) {
    815   SetError(base::StringPrintf("Failed to create/write thumbnail of %s.",
    816                               file_name.c_str()));
    817   SendResponse(false);
    818 }
    819 
    820 void WallpaperPrivateSaveThumbnailFunction::Success() {
    821   SendResponse(true);
    822 }
    823 
    824 void WallpaperPrivateSaveThumbnailFunction::Save(const std::string& data,
    825                                           const std::string& file_name) {
    826   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    827       sequence_token_));
    828   if (SaveData(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS, file_name, data)) {
    829     BrowserThread::PostTask(
    830       BrowserThread::UI, FROM_HERE,
    831       base::Bind(&WallpaperPrivateSaveThumbnailFunction::Success, this));
    832   } else {
    833     BrowserThread::PostTask(
    834           BrowserThread::UI, FROM_HERE,
    835           base::Bind(&WallpaperPrivateSaveThumbnailFunction::Failure,
    836                      this, file_name));
    837   }
    838 }
    839 
    840 WallpaperPrivateGetOfflineWallpaperListFunction::
    841     WallpaperPrivateGetOfflineWallpaperListFunction() {
    842 }
    843 
    844 WallpaperPrivateGetOfflineWallpaperListFunction::
    845     ~WallpaperPrivateGetOfflineWallpaperListFunction() {
    846 }
    847 
    848 bool WallpaperPrivateGetOfflineWallpaperListFunction::RunAsync() {
    849   sequence_token_ = BrowserThread::GetBlockingPool()->
    850       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    851   scoped_refptr<base::SequencedTaskRunner> task_runner =
    852       BrowserThread::GetBlockingPool()->
    853           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    854               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
    855 
    856   task_runner->PostTask(FROM_HERE,
    857       base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::GetList,
    858                  this));
    859   return true;
    860 }
    861 
    862 void WallpaperPrivateGetOfflineWallpaperListFunction::GetList() {
    863   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    864       sequence_token_));
    865   std::vector<std::string> file_list;
    866   base::FilePath wallpaper_dir;
    867   CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
    868   if (base::DirectoryExists(wallpaper_dir)) {
    869     base::FileEnumerator files(wallpaper_dir, false,
    870                                base::FileEnumerator::FILES);
    871     for (base::FilePath current = files.Next(); !current.empty();
    872          current = files.Next()) {
    873       std::string file_name = current.BaseName().RemoveExtension().value();
    874       // Do not add file name of small resolution wallpaper to the list.
    875       if (!EndsWith(file_name, chromeos::kSmallWallpaperSuffix, true))
    876         file_list.push_back(current.BaseName().value());
    877     }
    878   }
    879   BrowserThread::PostTask(
    880       BrowserThread::UI, FROM_HERE,
    881       base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::OnComplete,
    882                  this, file_list));
    883 }
    884 
    885 void WallpaperPrivateGetOfflineWallpaperListFunction::OnComplete(
    886     const std::vector<std::string>& file_list) {
    887   base::ListValue* results = new base::ListValue();
    888   results->AppendStrings(file_list);
    889   SetResult(results);
    890   SendResponse(true);
    891 }
    892