Home | History | Annotate | Download | only in extensions
      1 // Copyright 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_api.h"
      6 
      7 #include "ash/desktop_background/desktop_background_controller.h"
      8 #include "base/files/file_util.h"
      9 #include "base/lazy_instance.h"
     10 #include "base/path_service.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/threading/worker_pool.h"
     14 #include "chrome/browser/browser_process.h"
     15 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/common/chrome_paths.h"
     18 #include "chrome/common/extensions/extension_constants.h"
     19 #include "chrome/common/pref_names.h"
     20 #include "components/user_manager/user.h"
     21 #include "components/user_manager/user_manager.h"
     22 #include "net/base/load_flags.h"
     23 #include "net/http/http_status_code.h"
     24 #include "net/url_request/url_fetcher.h"
     25 #include "net/url_request/url_fetcher_delegate.h"
     26 #include "url/gurl.h"
     27 
     28 using base::BinaryValue;
     29 using content::BrowserThread;
     30 
     31 typedef base::Callback<void(bool success, const std::string&)> FetchCallback;
     32 
     33 namespace set_wallpaper = extensions::api::wallpaper::SetWallpaper;
     34 
     35 namespace {
     36 
     37 class WallpaperFetcher : public net::URLFetcherDelegate {
     38  public:
     39   WallpaperFetcher() {}
     40 
     41   virtual ~WallpaperFetcher() {}
     42 
     43   void FetchWallpaper(const GURL& url, FetchCallback callback) {
     44     CancelPreviousFetch();
     45     callback_ = callback;
     46     url_fetcher_.reset(net::URLFetcher::Create(url,
     47                                                net::URLFetcher::GET,
     48                                                this));
     49     url_fetcher_->SetRequestContext(
     50         g_browser_process->system_request_context());
     51     url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
     52     url_fetcher_->Start();
     53   }
     54 
     55  private:
     56   // URLFetcherDelegate overrides:
     57   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
     58     DCHECK(url_fetcher_.get() == source);
     59 
     60     bool success = source->GetStatus().is_success() &&
     61                    source->GetResponseCode() == net::HTTP_OK;
     62     std::string response;
     63     if (success) {
     64       source->GetResponseAsString(&response);
     65     } else {
     66       response = base::StringPrintf(
     67           "Downloading wallpaper %s failed. The response code is %d.",
     68           source->GetOriginalURL().ExtractFileName().c_str(),
     69           source->GetResponseCode());
     70     }
     71     url_fetcher_.reset();
     72     callback_.Run(success, response);
     73   }
     74 
     75   void CancelPreviousFetch() {
     76     if (url_fetcher_.get()) {
     77       callback_.Run(false, wallpaper_api_util::kCancelWallpaperMessage);
     78       url_fetcher_.reset();
     79     }
     80   }
     81 
     82   scoped_ptr<net::URLFetcher> url_fetcher_;
     83   FetchCallback callback_;
     84 };
     85 
     86 base::LazyInstance<WallpaperFetcher> g_wallpaper_fetcher =
     87     LAZY_INSTANCE_INITIALIZER;
     88 
     89 }  // namespace
     90 
     91 WallpaperSetWallpaperFunction::WallpaperSetWallpaperFunction() {
     92 }
     93 
     94 WallpaperSetWallpaperFunction::~WallpaperSetWallpaperFunction() {
     95 }
     96 
     97 bool WallpaperSetWallpaperFunction::RunAsync() {
     98   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     99   params_ = set_wallpaper::Params::Create(*args_);
    100   EXTENSION_FUNCTION_VALIDATE(params_);
    101 
    102   // Gets email address and username hash while at UI thread.
    103   user_id_ = user_manager::UserManager::Get()->GetLoggedInUser()->email();
    104   user_id_hash_ =
    105       user_manager::UserManager::Get()->GetLoggedInUser()->username_hash();
    106 
    107   if (params_->details.data) {
    108     StartDecode(*params_->details.data);
    109   } else {
    110     GURL wallpaper_url(*params_->details.url);
    111     if (wallpaper_url.is_valid()) {
    112       g_wallpaper_fetcher.Get().FetchWallpaper(
    113           wallpaper_url,
    114           base::Bind(&WallpaperSetWallpaperFunction::OnWallpaperFetched, this));
    115     } else {
    116       SetError("URL is invalid.");
    117       SendResponse(false);
    118     }
    119   }
    120   return true;
    121 }
    122 
    123 void WallpaperSetWallpaperFunction::OnWallpaperDecoded(
    124     const gfx::ImageSkia& image) {
    125   chromeos::WallpaperManager* wallpaper_manager =
    126       chromeos::WallpaperManager::Get();
    127   base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath(
    128       chromeos::kThumbnailWallpaperSubDir,
    129       user_id_hash_,
    130       params_->details.filename);
    131 
    132   sequence_token_ = BrowserThread::GetBlockingPool()->
    133       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
    134   scoped_refptr<base::SequencedTaskRunner> task_runner =
    135       BrowserThread::GetBlockingPool()->
    136           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
    137               base::SequencedWorkerPool::BLOCK_SHUTDOWN);
    138   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
    139       set_wallpaper::Params::Details::ToString(params_->details.layout));
    140   bool update_wallpaper =
    141       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
    142   wallpaper_manager->SetCustomWallpaper(user_id_,
    143                                         user_id_hash_,
    144                                         params_->details.filename,
    145                                         layout,
    146                                         user_manager::User::CUSTOMIZED,
    147                                         image,
    148                                         update_wallpaper);
    149   unsafe_wallpaper_decoder_ = NULL;
    150 
    151   if (params_->details.thumbnail) {
    152     image.EnsureRepsForSupportedScales();
    153     scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy());
    154     // Generates thumbnail before call api function callback. We can then
    155     // request thumbnail in the javascript callback.
    156     task_runner->PostTask(
    157         FROM_HERE,
    158         base::Bind(&WallpaperSetWallpaperFunction::GenerateThumbnail,
    159                    this,
    160                    thumbnail_path,
    161                    base::Passed(deep_copy.Pass())));
    162   } else {
    163     // Save current extenion name. It will be displayed in the component
    164     // wallpaper picker app. If current extension is the component wallpaper
    165     // picker, set an empty string.
    166     Profile* profile = Profile::FromBrowserContext(browser_context());
    167     if (extension()->id() == extension_misc::kWallpaperManagerId) {
    168       profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
    169                                      std::string());
    170     } else {
    171       profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
    172                                      extension()->name());
    173     }
    174     SendResponse(true);
    175   }
    176 }
    177 
    178 void WallpaperSetWallpaperFunction::GenerateThumbnail(
    179     const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
    180   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
    181       sequence_token_));
    182   if (!base::PathExists(thumbnail_path.DirName()))
    183     base::CreateDirectory(thumbnail_path.DirName());
    184 
    185   scoped_refptr<base::RefCountedBytes> data;
    186   chromeos::WallpaperManager::Get()->ResizeImage(
    187       *image,
    188       ash::WALLPAPER_LAYOUT_STRETCH,
    189       chromeos::kWallpaperThumbnailWidth,
    190       chromeos::kWallpaperThumbnailHeight,
    191       &data,
    192       NULL);
    193   BrowserThread::PostTask(
    194       BrowserThread::UI, FROM_HERE,
    195       base::Bind(
    196           &WallpaperSetWallpaperFunction::ThumbnailGenerated,
    197           this, data));
    198 }
    199 
    200 void WallpaperSetWallpaperFunction::ThumbnailGenerated(
    201     base::RefCountedBytes* data) {
    202   BinaryValue* result = BinaryValue::CreateWithCopiedBuffer(
    203       reinterpret_cast<const char*>(data->front()), data->size());
    204   SetResult(result);
    205   SendResponse(true);
    206 }
    207 
    208 void WallpaperSetWallpaperFunction::OnWallpaperFetched(
    209     bool success,
    210     const std::string& response) {
    211   if (success) {
    212     params_->details.data.reset(new std::string(response));
    213     StartDecode(*params_->details.data);
    214   } else {
    215     SetError(response);
    216     SendResponse(false);
    217   }
    218 }
    219