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