blob: e994f2d68da2251c02902cb807f4172dcc57a8ab [file] [log] [blame]
// 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/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/threading/worker_pool.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.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(bool success, 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 {
DCHECK(url_fetcher_.get() == source);
bool success = source->GetStatus().is_success() &&
source->GetResponseCode() == net::HTTP_OK;
std::string response;
if (success) {
source->GetResponseAsString(&response);
} else {
response = base::StringPrintf(
"Downloading wallpaper %s failed. The response code is %d.",
source->GetOriginalURL().ExtractFileName().c_str(),
source->GetResponseCode());
}
url_fetcher_.reset();
callback_.Run(success, response);
}
void CancelPreviousFetch() {
if (url_fetcher_.get()) {
callback_.Run(false, wallpaper_api_util::kCancelWallpaperMessage);
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::RunAsync() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
params_ = set_wallpaper::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params_);
// Gets email address and username hash while at UI thread.
user_id_ = user_manager::UserManager::Get()->GetLoggedInUser()->email();
user_id_hash_ =
user_manager::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& image) {
chromeos::WallpaperManager* wallpaper_manager =
chromeos::WallpaperManager::Get();
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));
bool update_wallpaper =
user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
wallpaper_manager->SetCustomWallpaper(user_id_,
user_id_hash_,
params_->details.name,
layout,
user_manager::User::CUSTOMIZED,
image,
update_wallpaper);
unsafe_wallpaper_decoder_ = NULL;
if (params_->details.thumbnail) {
image.EnsureRepsForSupportedScales();
scoped_ptr<gfx::ImageSkia> deep_copy(image.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.Pass())));
} else {
// Save current extenion name. It will be displayed in the component
// wallpaper picker app. If current extension is the component wallpaper
// picker, set an empty string.
Profile* profile = Profile::FromBrowserContext(browser_context());
if (extension()->id() == extension_misc::kWallpaperManagerId) {
profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
std::string());
} else {
profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
extension()->name());
}
SendResponse(true);
}
}
void WallpaperSetWallpaperFunction::GenerateThumbnail(
const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
sequence_token_));
if (!base::PathExists(thumbnail_path.DirName()))
base::CreateDirectory(thumbnail_path.DirName());
scoped_refptr<base::RefCountedBytes> data;
chromeos::WallpaperManager::Get()->ResizeImage(
*image,
ash::WALLPAPER_LAYOUT_STRETCH,
chromeos::kWallpaperThumbnailWidth,
chromeos::kWallpaperThumbnailHeight,
&data,
NULL);
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(
bool success,
const std::string& response) {
if (success) {
params_->details.wallpaper_data.reset(new std::string(response));
StartDecode(*params_->details.wallpaper_data);
} else {
SetError(response);
SendResponse(false);
}
}