• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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/user.h"
16 #include "chrome/browser/chromeos/login/users/user_manager.h"
17 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/common/pref_names.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"
26 #include "url/gurl.h"
27 
28 using base::BinaryValue;
29 using content::BrowserThread;
30 
31 typedef base::Callback<void(bool success, const std::string&)> FetchCallback;
32 
33 namespace set_wallpaper = extensions::api::wallpaper::SetWallpaper;
34 
35 namespace {
36 
37 class WallpaperFetcher : public net::URLFetcherDelegate {
38  public:
WallpaperFetcher()39   WallpaperFetcher() {}
40 
~WallpaperFetcher()41   virtual ~WallpaperFetcher() {}
42 
FetchWallpaper(const GURL & url,FetchCallback callback)43   void FetchWallpaper(const GURL& url, FetchCallback callback) {
44     CancelPreviousFetch();
45     callback_ = callback;
46     url_fetcher_.reset(net::URLFetcher::Create(url,
47                                                net::URLFetcher::GET,
48                                                this));
49     url_fetcher_->SetRequestContext(
50         g_browser_process->system_request_context());
51     url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
52     url_fetcher_->Start();
53   }
54 
55  private:
56   // URLFetcherDelegate overrides:
OnURLFetchComplete(const net::URLFetcher * source)57   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
58     DCHECK(url_fetcher_.get() == source);
59 
60     bool success = source->GetStatus().is_success() &&
61                    source->GetResponseCode() == net::HTTP_OK;
62     std::string response;
63     if (success) {
64       source->GetResponseAsString(&response);
65     } else {
66       response = base::StringPrintf(
67           "Downloading wallpaper %s failed. The response code is %d.",
68           source->GetOriginalURL().ExtractFileName().c_str(),
69           source->GetResponseCode());
70     }
71     url_fetcher_.reset();
72     callback_.Run(success, response);
73   }
74 
CancelPreviousFetch()75   void CancelPreviousFetch() {
76     if (url_fetcher_.get()) {
77       callback_.Run(false, wallpaper_api_util::kCancelWallpaperMessage);
78       url_fetcher_.reset();
79     }
80   }
81 
82   scoped_ptr<net::URLFetcher> url_fetcher_;
83   FetchCallback callback_;
84 };
85 
86 base::LazyInstance<WallpaperFetcher> g_wallpaper_fetcher =
87     LAZY_INSTANCE_INITIALIZER;
88 
89 }  // namespace
90 
WallpaperSetWallpaperFunction()91 WallpaperSetWallpaperFunction::WallpaperSetWallpaperFunction() {
92 }
93 
~WallpaperSetWallpaperFunction()94 WallpaperSetWallpaperFunction::~WallpaperSetWallpaperFunction() {
95 }
96 
RunAsync()97 bool WallpaperSetWallpaperFunction::RunAsync() {
98   DCHECK_CURRENTLY_ON(BrowserThread::UI);
99   params_ = set_wallpaper::Params::Create(*args_);
100   EXTENSION_FUNCTION_VALIDATE(params_);
101 
102   // Gets email address and username hash while at UI thread.
103   user_id_ = chromeos::UserManager::Get()->GetLoggedInUser()->email();
104   user_id_hash_ =
105       chromeos::UserManager::Get()->GetLoggedInUser()->username_hash();
106 
107   if (params_->details.wallpaper_data) {
108     StartDecode(*params_->details.wallpaper_data);
109   } else {
110     GURL wallpaper_url(*params_->details.url);
111     if (wallpaper_url.is_valid()) {
112       g_wallpaper_fetcher.Get().FetchWallpaper(
113           wallpaper_url,
114           base::Bind(&WallpaperSetWallpaperFunction::OnWallpaperFetched, this));
115     } else {
116       SetError("URL is invalid.");
117       SendResponse(false);
118     }
119   }
120   return true;
121 }
122 
OnWallpaperDecoded(const gfx::ImageSkia & image)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,
129       user_id_hash_,
130       params_->details.name);
131 
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_ == chromeos::UserManager::Get()->GetActiveUser()->email();
142   wallpaper_manager->SetCustomWallpaper(user_id_,
143                                         user_id_hash_,
144                                         params_->details.name,
145                                         layout,
146                                         chromeos::User::CUSTOMIZED,
147                                         image,
148                                         update_wallpaper);
149   unsafe_wallpaper_decoder_ = NULL;
150 
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(
157         FROM_HERE,
158         base::Bind(&WallpaperSetWallpaperFunction::GenerateThumbnail,
159                    this,
160                    thumbnail_path,
161                    base::Passed(deep_copy.Pass())));
162   } else {
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 (GetExtension()->id() == extension_misc::kWallpaperManagerId) {
168       profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
169                                      std::string());
170     } else {
171       profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
172                                      GetExtension()->name());
173     }
174     SendResponse(true);
175   }
176 }
177 
GenerateThumbnail(const base::FilePath & thumbnail_path,scoped_ptr<gfx::ImageSkia> image)178 void WallpaperSetWallpaperFunction::GenerateThumbnail(
179     const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
180   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
181       sequence_token_));
182   if (!base::PathExists(thumbnail_path.DirName()))
183     base::CreateDirectory(thumbnail_path.DirName());
184 
185   scoped_refptr<base::RefCountedBytes> data;
186   chromeos::WallpaperManager::Get()->ResizeImage(
187       *image,
188       ash::WALLPAPER_LAYOUT_STRETCH,
189       chromeos::kWallpaperThumbnailWidth,
190       chromeos::kWallpaperThumbnailHeight,
191       &data,
192       NULL);
193   BrowserThread::PostTask(
194       BrowserThread::UI, FROM_HERE,
195       base::Bind(
196           &WallpaperSetWallpaperFunction::ThumbnailGenerated,
197           this, data));
198 }
199 
ThumbnailGenerated(base::RefCountedBytes * data)200 void WallpaperSetWallpaperFunction::ThumbnailGenerated(
201     base::RefCountedBytes* data) {
202   BinaryValue* result = BinaryValue::CreateWithCopiedBuffer(
203       reinterpret_cast<const char*>(data->front()), data->size());
204   SetResult(result);
205   SendResponse(true);
206 }
207 
OnWallpaperFetched(bool success,const std::string & response)208 void WallpaperSetWallpaperFunction::OnWallpaperFetched(
209     bool success,
210     const std::string& response) {
211   if (success) {
212     params_->details.wallpaper_data.reset(new std::string(response));
213     StartDecode(*params_->details.wallpaper_data);
214   } else {
215     SetError(response);
216     SendResponse(false);
217   }
218 }
219