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"
10 #include "ash/desktop_background/desktop_background_controller.h"
11 #include "base/files/file_util.h"
12 #include "base/lazy_instance.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/threading/worker_pool.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chromeos/extensions/wallpaper_private_api.h"
18 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/chrome_paths.h"
21 #include "chrome/common/extensions/extension_constants.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/user_manager/user.h"
24 #include "components/user_manager/user_manager.h"
25 #include "components/wallpaper/wallpaper_layout.h"
26 #include "extensions/browser/event_router.h"
27 #include "net/base/load_flags.h"
28 #include "net/http/http_status_code.h"
29 #include "net/url_request/url_fetcher.h"
30 #include "net/url_request/url_fetcher_delegate.h"
33 using base::BinaryValue
;
34 using content::BrowserThread
;
36 typedef base::Callback
<void(bool success
, const std::string
&)> FetchCallback
;
38 namespace set_wallpaper
= extensions::api::wallpaper::SetWallpaper
;
42 class WallpaperFetcher
: public net::URLFetcherDelegate
{
46 ~WallpaperFetcher() override
{}
48 void FetchWallpaper(const GURL
& url
, FetchCallback callback
) {
49 CancelPreviousFetch();
51 url_fetcher_
= net::URLFetcher::Create(url
, net::URLFetcher::GET
, this);
52 url_fetcher_
->SetRequestContext(
53 g_browser_process
->system_request_context());
54 url_fetcher_
->SetLoadFlags(net::LOAD_DISABLE_CACHE
);
55 url_fetcher_
->Start();
59 // URLFetcherDelegate overrides:
60 void OnURLFetchComplete(const net::URLFetcher
* source
) override
{
61 DCHECK(url_fetcher_
.get() == source
);
63 bool success
= source
->GetStatus().is_success() &&
64 source
->GetResponseCode() == net::HTTP_OK
;
67 source
->GetResponseAsString(&response
);
69 response
= base::StringPrintf(
70 "Downloading wallpaper %s failed. The response code is %d.",
71 source
->GetOriginalURL().ExtractFileName().c_str(),
72 source
->GetResponseCode());
75 callback_
.Run(success
, response
);
79 void CancelPreviousFetch() {
80 if (url_fetcher_
.get()) {
81 callback_
.Run(false, wallpaper_api_util::kCancelWallpaperMessage
);
87 scoped_ptr
<net::URLFetcher
> url_fetcher_
;
88 FetchCallback callback_
;
91 base::LazyInstance
<WallpaperFetcher
> g_wallpaper_fetcher
=
92 LAZY_INSTANCE_INITIALIZER
;
96 WallpaperSetWallpaperFunction::WallpaperSetWallpaperFunction() {
99 WallpaperSetWallpaperFunction::~WallpaperSetWallpaperFunction() {
102 bool WallpaperSetWallpaperFunction::RunAsync() {
103 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
104 params_
= set_wallpaper::Params::Create(*args_
);
105 EXTENSION_FUNCTION_VALIDATE(params_
);
107 // Gets email address and username hash while at UI thread.
108 user_id_
= user_manager::UserManager::Get()->GetLoggedInUser()->email();
110 user_manager::UserManager::Get()->GetLoggedInUser()->username_hash();
112 if (params_
->details
.data
) {
113 StartDecode(*params_
->details
.data
);
115 GURL
wallpaper_url(*params_
->details
.url
);
116 if (wallpaper_url
.is_valid()) {
117 g_wallpaper_fetcher
.Get().FetchWallpaper(
119 base::Bind(&WallpaperSetWallpaperFunction::OnWallpaperFetched
, this));
121 SetError("URL is invalid.");
128 void WallpaperSetWallpaperFunction::OnWallpaperDecoded(
129 const gfx::ImageSkia
& image
) {
130 chromeos::WallpaperManager
* wallpaper_manager
=
131 chromeos::WallpaperManager::Get();
132 base::FilePath thumbnail_path
= wallpaper_manager
->GetCustomWallpaperPath(
133 wallpaper::kThumbnailWallpaperSubDir
, user_id_hash_
,
134 params_
->details
.filename
);
136 sequence_token_
= BrowserThread::GetBlockingPool()->GetNamedSequenceToken(
137 wallpaper::kWallpaperSequenceTokenName
);
138 scoped_refptr
<base::SequencedTaskRunner
> task_runner
=
139 BrowserThread::GetBlockingPool()->
140 GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_
,
141 base::SequencedWorkerPool::BLOCK_SHUTDOWN
);
142 wallpaper::WallpaperLayout layout
= wallpaper_api_util::GetLayoutEnum(
143 extensions::api::wallpaper::ToString(params_
->details
.layout
));
144 bool update_wallpaper
=
145 user_id_
== user_manager::UserManager::Get()->GetActiveUser()->email();
146 wallpaper_manager
->SetCustomWallpaper(user_id_
,
148 params_
->details
.filename
,
150 user_manager::User::CUSTOMIZED
,
153 unsafe_wallpaper_decoder_
= NULL
;
155 if (params_
->details
.thumbnail
) {
156 image
.EnsureRepsForSupportedScales();
157 scoped_ptr
<gfx::ImageSkia
> deep_copy(image
.DeepCopy());
158 // Generates thumbnail before call api function callback. We can then
159 // request thumbnail in the javascript callback.
160 task_runner
->PostTask(
162 base::Bind(&WallpaperSetWallpaperFunction::GenerateThumbnail
,
165 base::Passed(deep_copy
.Pass())));
167 // Save current extenion name. It will be displayed in the component
168 // wallpaper picker app. If current extension is the component wallpaper
169 // picker, set an empty string.
170 Profile
* profile
= Profile::FromBrowserContext(browser_context());
171 if (extension()->id() == extension_misc::kWallpaperManagerId
) {
172 profile
->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName
,
175 profile
->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName
,
176 extension()->name());
181 // Inform the native Wallpaper Picker Application that the current wallpaper
182 // has been modified by a third party application.
183 Profile
* profile
= Profile::FromBrowserContext(browser_context());
184 extensions::EventRouter
* event_router
= extensions::EventRouter::Get(profile
);
185 scoped_ptr
<base::ListValue
> event_args(new base::ListValue());
186 scoped_ptr
<extensions::Event
> event(new extensions::Event(
187 extensions::events::WALLPAPER_PRIVATE_ON_WALLPAPER_CHANGED_BY_3RD_PARTY
,
188 extensions::api::wallpaper_private::OnWallpaperChangedBy3rdParty::
191 event_router
->DispatchEventToExtension(extension_misc::kWallpaperManagerId
,
195 void WallpaperSetWallpaperFunction::GenerateThumbnail(
196 const base::FilePath
& thumbnail_path
, scoped_ptr
<gfx::ImageSkia
> image
) {
197 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
199 if (!base::PathExists(thumbnail_path
.DirName()))
200 base::CreateDirectory(thumbnail_path
.DirName());
202 scoped_refptr
<base::RefCountedBytes
> data
;
203 chromeos::WallpaperManager::Get()->ResizeImage(
204 *image
, wallpaper::WALLPAPER_LAYOUT_STRETCH
,
205 wallpaper::kWallpaperThumbnailWidth
, wallpaper::kWallpaperThumbnailHeight
,
207 BrowserThread::PostTask(
208 BrowserThread::UI
, FROM_HERE
,
210 &WallpaperSetWallpaperFunction::ThumbnailGenerated
,
214 void WallpaperSetWallpaperFunction::ThumbnailGenerated(
215 base::RefCountedBytes
* data
) {
216 BinaryValue
* result
= BinaryValue::CreateWithCopiedBuffer(
217 reinterpret_cast<const char*>(data
->front()), data
->size());
222 void WallpaperSetWallpaperFunction::OnWallpaperFetched(
224 const std::string
& response
) {
226 params_
->details
.data
.reset(
227 new std::vector
<char>(response
.begin(), response
.end()));
228 StartDecode(*params_
->details
.data
);