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