blob: c2fd971e5ac8cef28d4da020002c25915277e950 [file] [log] [blame]
// Copyright 2014 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/android/logo_service.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/android/chrome_feature_list.h"
#include "chrome/browser/image_decoder.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
#include "chrome/common/chrome_switches.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/search_engines/template_url_service.h"
#include "components/search_provider_logos/fixed_logo_api.h"
#include "components/search_provider_logos/google_logo_api.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context_getter.h"
using content::BrowserThread;
using search_provider_logos::Logo;
using search_provider_logos::LogoDelegate;
using search_provider_logos::LogoTracker;
namespace {
const char kCachedLogoDirectory[] = "Search Logo";
const int kDecodeLogoTimeoutSeconds = 30;
// Returns the URL where the doodle can be downloaded, e.g.
// https://www.google.com/async/newtab_mobile. This depends on the user's
// Google domain.
GURL GetGoogleDoodleURL(Profile* profile) {
GURL google_base_url(UIThreadSearchTermsData(profile).GoogleBaseURLValue());
const char kGoogleDoodleURLPath[] = "async/newtab_mobile";
GURL::Replacements replacements;
replacements.SetPathStr(kGoogleDoodleURLPath);
return google_base_url.ReplaceComponents(replacements);
}
class LogoDecoderDelegate : public ImageDecoder::ImageRequest {
public:
LogoDecoderDelegate(
const base::Callback<void(const SkBitmap&)>& image_decoded_callback)
: image_decoded_callback_(image_decoded_callback),
weak_ptr_factory_(this) {
// If the ImageDecoder crashes or otherwise never completes, call
// OnImageDecodeTimedOut() eventually to ensure that image_decoded_callback_
// is run.
task_runner()->PostDelayedTask(
FROM_HERE,
base::Bind(&LogoDecoderDelegate::OnDecodeImageFailed,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds));
}
~LogoDecoderDelegate() override {}
// ImageDecoder::ImageRequest:
void OnImageDecoded(const SkBitmap& decoded_image) override {
image_decoded_callback_.Run(decoded_image);
delete this;
}
void OnDecodeImageFailed() override {
image_decoded_callback_.Run(SkBitmap());
delete this;
}
private:
base::Callback<void(const SkBitmap&)> image_decoded_callback_;
base::WeakPtrFactory<LogoDecoderDelegate> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(LogoDecoderDelegate);
};
class ChromeLogoDelegate : public search_provider_logos::LogoDelegate {
public:
ChromeLogoDelegate() {}
~ChromeLogoDelegate() override {}
// search_provider_logos::LogoDelegate:
void DecodeUntrustedImage(
const scoped_refptr<base::RefCountedString>& encoded_image,
base::Callback<void(const SkBitmap&)> image_decoded_callback) override {
// TODO(bauerb): Switch to the components/image_fetcher implementation.
auto delegate =
base::MakeUnique<LogoDecoderDelegate>(image_decoded_callback);
ImageDecoder::Start(delegate.release(), encoded_image->data());
}
private:
DISALLOW_COPY_AND_ASSIGN(ChromeLogoDelegate);
};
} // namespace
// LogoService ----------------------------------------------------------------
LogoService::LogoService(Profile* profile) : profile_(profile) {
}
LogoService::~LogoService() {
}
void LogoService::GetLogo(search_provider_logos::LogoObserver* observer) {
TemplateURLService* template_url_service =
TemplateURLServiceFactory::GetForProfile(profile_);
if (!template_url_service)
return;
const TemplateURL* template_url =
template_url_service->GetDefaultSearchProvider();
if (!template_url)
return;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
GURL logo_url;
if (command_line->HasSwitch(switches::kSearchProviderLogoURL)) {
logo_url = GURL(
command_line->GetSwitchValueASCII(switches::kSearchProviderLogoURL));
} else {
logo_url = template_url->logo_url();
}
const bool use_fixed_logo = logo_url.is_valid();
if (!template_url->url_ref().HasGoogleBaseURLs(
template_url_service->search_terms_data()) &&
!use_fixed_logo) {
return;
}
if (!logo_tracker_) {
logo_tracker_ = base::MakeUnique<LogoTracker>(
profile_->GetPath().Append(kCachedLogoDirectory),
profile_->GetRequestContext(), base::MakeUnique<ChromeLogoDelegate>());
}
GURL url = use_fixed_logo ? logo_url : GetGoogleDoodleURL(profile_);
auto parse_logo_response_callback =
use_fixed_logo
? base::Bind(&search_provider_logos::ParseFixedLogoResponse)
: base::Bind(&search_provider_logos::GoogleParseLogoResponse);
bool use_gray_background =
!base::FeatureList::IsEnabled(chrome::android::kChromeHomeFeature);
auto append_query_params_callback =
use_fixed_logo
? base::Bind(&search_provider_logos::UseFixedLogoUrl)
: base::Bind(&search_provider_logos::GoogleAppendQueryparamsToLogoURL,
use_gray_background);
logo_tracker_->SetServerAPI(url, parse_logo_response_callback,
append_query_params_callback);
logo_tracker_->GetLogo(observer);
}
// LogoServiceFactory ---------------------------------------------------------
// static
LogoService* LogoServiceFactory::GetForProfile(Profile* profile) {
return static_cast<LogoService*>(
GetInstance()->GetServiceForBrowserContext(profile, true));
}
// static
LogoServiceFactory* LogoServiceFactory::GetInstance() {
return base::Singleton<LogoServiceFactory>::get();
}
LogoServiceFactory::LogoServiceFactory()
: BrowserContextKeyedServiceFactory(
"LogoService",
BrowserContextDependencyManager::GetInstance()) {
}
LogoServiceFactory::~LogoServiceFactory() {}
KeyedService* LogoServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
Profile* profile = static_cast<Profile*>(context);
DCHECK(!profile->IsOffTheRecord());
return new LogoService(profile);
}