1 // Copyright 2014 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/android/logo_service.h"
7 #include "base/memory/weak_ptr.h"
8 #include "chrome/browser/google/google_profile_helper.h"
9 #include "chrome/browser/image_decoder.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/search_engines/template_url_service_factory.h"
12 #include "components/google/core/browser/google_util.h"
13 #include "components/keyed_service/content/browser_context_dependency_manager.h"
14 #include "components/search_engines/template_url_service.h"
15 #include "components/search_provider_logos/google_logo_api.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/url_request/url_request_context_getter.h"
19 using content::BrowserThread
;
20 using search_provider_logos::Logo
;
21 using search_provider_logos::LogoDelegate
;
22 using search_provider_logos::LogoTracker
;
26 const char kGoogleDoodleURLPath
[] = "async/newtab_mobile";
27 const char kCachedLogoDirectory
[] = "Search Logo";
28 const int kDecodeLogoTimeoutSeconds
= 30;
30 // Returns the URL where the doodle can be downloaded, e.g.
31 // https://www.google.com/async/newtab_mobile. This depends on the user's
33 GURL
GetGoogleDoodleURL(Profile
* profile
) {
34 // SetPathStr() requires its argument to stay in scope as long as
35 // |replacements| is, so a std::string is needed, instead of a char*.
36 std::string path
= kGoogleDoodleURLPath
;
37 GURL::Replacements replacements
;
38 replacements
.SetPathStr(path
);
40 GURL
base_url(google_util::CommandLineGoogleBaseURL());
41 if (!base_url
.is_valid())
42 base_url
= google_profile_helper::GetGoogleHomePageURL(profile
);
43 return base_url
.ReplaceComponents(replacements
);
46 class LogoDecoderDelegate
: public ImageDecoder::Delegate
{
49 const scoped_refptr
<ImageDecoder
>& image_decoder
,
50 const base::Callback
<void(const SkBitmap
&)>& image_decoded_callback
)
51 : image_decoder_(image_decoder
),
52 image_decoded_callback_(image_decoded_callback
),
53 weak_ptr_factory_(this) {
54 // If the ImageDecoder crashes or otherwise never completes, call
55 // OnImageDecodeTimedOut() eventually to ensure that image_decoded_callback_
57 base::MessageLoopProxy::current()->PostDelayedTask(
59 base::Bind(&LogoDecoderDelegate::OnDecodeImageFailed
,
60 weak_ptr_factory_
.GetWeakPtr(),
61 (const ImageDecoder
*) NULL
),
62 base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds
));
65 virtual ~LogoDecoderDelegate() {
66 image_decoder_
->set_delegate(NULL
);
69 // ImageDecoder::Delegate:
70 virtual void OnImageDecoded(const ImageDecoder
* decoder
,
71 const SkBitmap
& decoded_image
) override
{
72 image_decoded_callback_
.Run(decoded_image
);
76 virtual void OnDecodeImageFailed(const ImageDecoder
* decoder
) override
{
77 image_decoded_callback_
.Run(SkBitmap());
82 scoped_refptr
<ImageDecoder
> image_decoder_
;
83 base::Callback
<void(const SkBitmap
&)> image_decoded_callback_
;
84 base::WeakPtrFactory
<LogoDecoderDelegate
> weak_ptr_factory_
;
86 DISALLOW_COPY_AND_ASSIGN(LogoDecoderDelegate
);
89 class ChromeLogoDelegate
: public search_provider_logos::LogoDelegate
{
91 ChromeLogoDelegate() {}
92 virtual ~ChromeLogoDelegate() {}
94 // search_provider_logos::LogoDelegate:
95 virtual void DecodeUntrustedImage(
96 const scoped_refptr
<base::RefCountedString
>& encoded_image
,
97 base::Callback
<void(const SkBitmap
&)> image_decoded_callback
) override
{
98 scoped_refptr
<ImageDecoder
> image_decoder
= new ImageDecoder(
100 encoded_image
->data(),
101 ImageDecoder::DEFAULT_CODEC
);
102 LogoDecoderDelegate
* delegate
=
103 new LogoDecoderDelegate(image_decoder
, image_decoded_callback
);
104 image_decoder
->set_delegate(delegate
);
105 image_decoder
->Start(base::MessageLoopProxy::current());
109 DISALLOW_COPY_AND_ASSIGN(ChromeLogoDelegate
);
114 // LogoService ----------------------------------------------------------------
116 LogoService::LogoService(Profile
* profile
) : profile_(profile
) {
119 LogoService::~LogoService() {
122 void LogoService::GetLogo(search_provider_logos::LogoObserver
* observer
) {
123 TemplateURLService
* template_url_service
=
124 TemplateURLServiceFactory::GetForProfile(profile_
);
125 if (!template_url_service
)
128 TemplateURL
* template_url
= template_url_service
->GetDefaultSearchProvider();
129 if (!template_url
|| !template_url
->url_ref().HasGoogleBaseURLs(
130 template_url_service
->search_terms_data()))
133 if (!logo_tracker_
) {
134 logo_tracker_
.reset(new LogoTracker(
135 profile_
->GetPath().Append(kCachedLogoDirectory
),
136 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
137 BrowserThread::GetBlockingPool(),
138 profile_
->GetRequestContext(),
139 scoped_ptr
<search_provider_logos::LogoDelegate
>(
140 new ChromeLogoDelegate())));
143 logo_tracker_
->SetServerAPI(
144 GetGoogleDoodleURL(profile_
),
145 base::Bind(&search_provider_logos::GoogleParseLogoResponse
),
146 base::Bind(&search_provider_logos::GoogleAppendFingerprintToLogoURL
));
147 logo_tracker_
->GetLogo(observer
);
150 // LogoServiceFactory ---------------------------------------------------------
153 LogoService
* LogoServiceFactory::GetForProfile(Profile
* profile
) {
154 return static_cast<LogoService
*>(
155 GetInstance()->GetServiceForBrowserContext(profile
, true));
159 LogoServiceFactory
* LogoServiceFactory::GetInstance() {
160 return Singleton
<LogoServiceFactory
>::get();
163 LogoServiceFactory::LogoServiceFactory()
164 : BrowserContextKeyedServiceFactory(
166 BrowserContextDependencyManager::GetInstance()) {
169 LogoServiceFactory::~LogoServiceFactory() {}
171 KeyedService
* LogoServiceFactory::BuildServiceInstanceFor(
172 content::BrowserContext
* context
) const {
173 Profile
* profile
= static_cast<Profile
*>(context
);
174 DCHECK(!profile
->IsOffTheRecord());
175 return new LogoService(profile
);