| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/extensions/wallpaper_api.h" |
| |
| #include "ash/desktop_background/desktop_background_controller.h" |
| #include "base/file_util.h" |
| #include "base/lazy_instance.h" |
| #include "base/path_service.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/threading/worker_pool.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/login/user.h" |
| #include "chrome/browser/chromeos/login/user_manager.h" |
| #include "chrome/browser/chromeos/login/wallpaper_manager.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "net/base/load_flags.h" |
| #include "net/url_request/url_fetcher.h" |
| #include "net/url_request/url_fetcher_delegate.h" |
| #include "url/gurl.h" |
| |
| using base::BinaryValue; |
| using content::BrowserThread; |
| |
| typedef base::Callback<void(net::URLRequestStatus::Status, const std::string&)> |
| FetchCallback; |
| |
| namespace set_wallpaper = extensions::api::wallpaper::SetWallpaper; |
| |
| namespace { |
| |
| class WallpaperFetcher : public net::URLFetcherDelegate { |
| public: |
| WallpaperFetcher() {} |
| |
| virtual ~WallpaperFetcher() {} |
| |
| void FetchWallpaper(const GURL& url, FetchCallback callback) { |
| CancelPreviousFetch(); |
| callback_ = callback; |
| url_fetcher_.reset(net::URLFetcher::Create(url, |
| net::URLFetcher::GET, |
| this)); |
| url_fetcher_->SetRequestContext( |
| g_browser_process->system_request_context()); |
| url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
| url_fetcher_->Start(); |
| } |
| |
| private: |
| // URLFetcherDelegate overrides: |
| virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { |
| net::URLRequestStatus::Status status = source->GetStatus().status(); |
| std::string response; |
| if (status == net::URLRequestStatus::SUCCESS) { |
| url_fetcher_->GetResponseAsString(&response); |
| } else { |
| response = source->GetStatus().error(); |
| } |
| url_fetcher_.reset(); |
| callback_.Run(status, response); |
| } |
| |
| void CancelPreviousFetch() { |
| if (url_fetcher_.get()) { |
| std::string error = base::StringPrintf( |
| "Downloading wallpaper %s is canceled.", |
| url_fetcher_->GetOriginalURL().ExtractFileName().c_str()); |
| callback_.Run(net::URLRequestStatus::CANCELED, error); |
| url_fetcher_.reset(); |
| } |
| } |
| |
| scoped_ptr<net::URLFetcher> url_fetcher_; |
| FetchCallback callback_; |
| }; |
| |
| base::LazyInstance<WallpaperFetcher> g_wallpaper_fetcher = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| } // namespace |
| |
| WallpaperSetWallpaperFunction::WallpaperSetWallpaperFunction() { |
| } |
| |
| WallpaperSetWallpaperFunction::~WallpaperSetWallpaperFunction() { |
| } |
| |
| bool WallpaperSetWallpaperFunction::RunImpl() { |
| params_ = set_wallpaper::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_); |
| |
| // Gets email address and username hash while at UI thread. |
| email_ = chromeos::UserManager::Get()->GetLoggedInUser()->email(); |
| user_id_hash_ = |
| chromeos::UserManager::Get()->GetLoggedInUser()->username_hash(); |
| |
| if (params_->details.wallpaper_data) { |
| StartDecode(*params_->details.wallpaper_data); |
| } else { |
| GURL wallpaper_url(*params_->details.url); |
| if (wallpaper_url.is_valid()) { |
| g_wallpaper_fetcher.Get().FetchWallpaper( |
| wallpaper_url, |
| base::Bind(&WallpaperSetWallpaperFunction::OnWallpaperFetched, |
| this)); |
| } else { |
| SetError("URL is invalid."); |
| SendResponse(false); |
| } |
| } |
| return true; |
| } |
| |
| void WallpaperSetWallpaperFunction::OnWallpaperDecoded( |
| const gfx::ImageSkia& wallpaper) { |
| chromeos::WallpaperManager* wallpaper_manager = |
| chromeos::WallpaperManager::Get(); |
| chromeos::UserImage::RawImage raw_image( |
| params_->details.wallpaper_data->begin(), |
| params_->details.wallpaper_data->end()); |
| chromeos::UserImage image(wallpaper, raw_image); |
| base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath( |
| chromeos::kThumbnailWallpaperSubDir, |
| user_id_hash_, |
| params_->details.name); |
| |
| sequence_token_ = BrowserThread::GetBlockingPool()-> |
| GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName); |
| scoped_refptr<base::SequencedTaskRunner> task_runner = |
| BrowserThread::GetBlockingPool()-> |
| GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_, |
| base::SequencedWorkerPool::BLOCK_SHUTDOWN); |
| ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum( |
| set_wallpaper::Params::Details::ToString(params_->details.layout)); |
| wallpaper_manager->SetCustomWallpaper(email_, |
| user_id_hash_, |
| params_->details.name, |
| layout, |
| chromeos::User::CUSTOMIZED, |
| image); |
| unsafe_wallpaper_decoder_ = NULL; |
| |
| if (params_->details.thumbnail) { |
| wallpaper.EnsureRepsForSupportedScales(); |
| scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper.DeepCopy()); |
| // Generates thumbnail before call api function callback. We can then |
| // request thumbnail in the javascript callback. |
| task_runner->PostTask(FROM_HERE, |
| base::Bind( |
| &WallpaperSetWallpaperFunction::GenerateThumbnail, |
| this, thumbnail_path, base::Passed(&deep_copy))); |
| } else { |
| SendResponse(true); |
| } |
| } |
| |
| void WallpaperSetWallpaperFunction::GenerateThumbnail( |
| const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) { |
| DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( |
| sequence_token_)); |
| chromeos::UserImage wallpaper(*image.get()); |
| if (!base::PathExists(thumbnail_path.DirName())) |
| file_util::CreateDirectory(thumbnail_path.DirName()); |
| |
| scoped_refptr<base::RefCountedBytes> data; |
| chromeos::WallpaperManager::Get()->ResizeWallpaper( |
| wallpaper, |
| ash::WALLPAPER_LAYOUT_STRETCH, |
| ash::kWallpaperThumbnailWidth, |
| ash::kWallpaperThumbnailHeight, |
| &data); |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind( |
| &WallpaperSetWallpaperFunction::ThumbnailGenerated, |
| this, data)); |
| } |
| |
| void WallpaperSetWallpaperFunction::ThumbnailGenerated( |
| base::RefCountedBytes* data) { |
| BinaryValue* result = BinaryValue::CreateWithCopiedBuffer( |
| reinterpret_cast<const char*>(data->front()), data->size()); |
| SetResult(result); |
| SendResponse(true); |
| } |
| |
| void WallpaperSetWallpaperFunction::OnWallpaperFetched( |
| net::URLRequestStatus::Status status, const std::string& response) { |
| if (status == net::URLRequestStatus::SUCCESS) { |
| params_->details.wallpaper_data.reset(new std::string(response)); |
| StartDecode(*params_->details.wallpaper_data); |
| } else { |
| SetError(response); |
| SendResponse(false); |
| } |
| } |