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