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:
WallpaperFetcher()35 WallpaperFetcher() {}
36
~WallpaperFetcher()37 virtual ~WallpaperFetcher() {}
38
FetchWallpaper(const GURL & url,FetchCallback callback)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:
OnURLFetchComplete(const net::URLFetcher * source)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
CancelPreviousFetch()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
WallpaperSetWallpaperFunction()84 WallpaperSetWallpaperFunction::WallpaperSetWallpaperFunction() {
85 }
86
~WallpaperSetWallpaperFunction()87 WallpaperSetWallpaperFunction::~WallpaperSetWallpaperFunction() {
88 }
89
RunImpl()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
OnWallpaperDecoded(const gfx::ImageSkia & wallpaper)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
GenerateThumbnail(const base::FilePath & thumbnail_path,scoped_ptr<gfx::ImageSkia> image)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
ThumbnailGenerated(base::RefCountedBytes * data)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
OnWallpaperFetched(net::URLRequestStatus::Status status,const std::string & response)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