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.
5 #include "chrome/browser/chromeos/extensions/wallpaper_api.h"
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"
28 using base::BinaryValue;
29 using content::BrowserThread;
31 typedef base::Callback<void(bool success, const std::string&)> FetchCallback;
33 namespace set_wallpaper = extensions::api::wallpaper::SetWallpaper;
37 class WallpaperFetcher : public net::URLFetcherDelegate {
41 virtual ~WallpaperFetcher() {}
43 void FetchWallpaper(const GURL& url, FetchCallback callback) {
44 CancelPreviousFetch();
46 url_fetcher_.reset(net::URLFetcher::Create(url,
49 url_fetcher_->SetRequestContext(
50 g_browser_process->system_request_context());
51 url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
52 url_fetcher_->Start();
56 // URLFetcherDelegate overrides:
57 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
58 DCHECK(url_fetcher_.get() == source);
60 bool success = source->GetStatus().is_success() &&
61 source->GetResponseCode() == net::HTTP_OK;
64 source->GetResponseAsString(&response);
66 response = base::StringPrintf(
67 "Downloading wallpaper %s failed. The response code is %d.",
68 source->GetOriginalURL().ExtractFileName().c_str(),
69 source->GetResponseCode());
72 callback_.Run(success, response);
75 void CancelPreviousFetch() {
76 if (url_fetcher_.get()) {
77 callback_.Run(false, wallpaper_api_util::kCancelWallpaperMessage);
82 scoped_ptr<net::URLFetcher> url_fetcher_;
83 FetchCallback callback_;
86 base::LazyInstance<WallpaperFetcher> g_wallpaper_fetcher =
87 LAZY_INSTANCE_INITIALIZER;
91 WallpaperSetWallpaperFunction::WallpaperSetWallpaperFunction() {
94 WallpaperSetWallpaperFunction::~WallpaperSetWallpaperFunction() {
97 bool WallpaperSetWallpaperFunction::RunAsync() {
98 DCHECK_CURRENTLY_ON(BrowserThread::UI);
99 params_ = set_wallpaper::Params::Create(*args_);
100 EXTENSION_FUNCTION_VALIDATE(params_);
102 // Gets email address and username hash while at UI thread.
103 user_id_ = user_manager::UserManager::Get()->GetLoggedInUser()->email();
105 user_manager::UserManager::Get()->GetLoggedInUser()->username_hash();
107 if (params_->details.data) {
108 StartDecode(*params_->details.data);
110 GURL wallpaper_url(*params_->details.url);
111 if (wallpaper_url.is_valid()) {
112 g_wallpaper_fetcher.Get().FetchWallpaper(
114 base::Bind(&WallpaperSetWallpaperFunction::OnWallpaperFetched, this));
116 SetError("URL is invalid.");
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,
130 params_->details.filename);
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_,
144 params_->details.filename,
146 user_manager::User::CUSTOMIZED,
149 unsafe_wallpaper_decoder_ = NULL;
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(
158 base::Bind(&WallpaperSetWallpaperFunction::GenerateThumbnail,
161 base::Passed(deep_copy.Pass())));
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,
171 profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
172 extension()->name());
178 void WallpaperSetWallpaperFunction::GenerateThumbnail(
179 const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
180 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
182 if (!base::PathExists(thumbnail_path.DirName()))
183 base::CreateDirectory(thumbnail_path.DirName());
185 scoped_refptr<base::RefCountedBytes> data;
186 chromeos::WallpaperManager::Get()->ResizeImage(
188 ash::WALLPAPER_LAYOUT_STRETCH,
189 chromeos::kWallpaperThumbnailWidth,
190 chromeos::kWallpaperThumbnailHeight,
193 BrowserThread::PostTask(
194 BrowserThread::UI, FROM_HERE,
196 &WallpaperSetWallpaperFunction::ThumbnailGenerated,
200 void WallpaperSetWallpaperFunction::ThumbnailGenerated(
201 base::RefCountedBytes* data) {
202 BinaryValue* result = BinaryValue::CreateWithCopiedBuffer(
203 reinterpret_cast<const char*>(data->front()), data->size());
208 void WallpaperSetWallpaperFunction::OnWallpaperFetched(
210 const std::string& response) {
212 params_->details.data.reset(new std::string(response));
213 StartDecode(*params_->details.data);