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