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/image_decoder.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/search_engines/template_url_service_factory.h"
11 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
12 #include "components/keyed_service/content/browser_context_dependency_manager.h"
13 #include "components/search_engines/template_url_service.h"
14 #include "components/search_provider_logos/google_logo_api.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "net/url_request/url_request_context_getter.h"
18 using content::BrowserThread
;
19 using search_provider_logos::Logo
;
20 using search_provider_logos::LogoDelegate
;
21 using search_provider_logos::LogoTracker
;
25 const char kCachedLogoDirectory
[] = "Search Logo";
26 const int kDecodeLogoTimeoutSeconds
= 30;
28 // Returns the URL where the doodle can be downloaded, e.g.
29 // https://www.google.com/async/newtab_mobile. This depends on the user's
31 GURL
GetGoogleDoodleURL(Profile
* profile
) {
32 GURL
google_base_url(UIThreadSearchTermsData(profile
).GoogleBaseURLValue());
33 const char kGoogleDoodleURLPath
[] = "async/newtab_mobile";
34 GURL::Replacements replacements
;
35 replacements
.SetPathStr(kGoogleDoodleURLPath
);
36 return google_base_url
.ReplaceComponents(replacements
);
39 class LogoDecoderDelegate
: public ImageDecoder::Delegate
{
42 const scoped_refptr
<ImageDecoder
>& image_decoder
,
43 const base::Callback
<void(const SkBitmap
&)>& image_decoded_callback
)
44 : image_decoder_(image_decoder
),
45 image_decoded_callback_(image_decoded_callback
),
46 weak_ptr_factory_(this) {
47 // If the ImageDecoder crashes or otherwise never completes, call
48 // OnImageDecodeTimedOut() eventually to ensure that image_decoded_callback_
50 base::MessageLoopProxy::current()->PostDelayedTask(
52 base::Bind(&LogoDecoderDelegate::OnDecodeImageFailed
,
53 weak_ptr_factory_
.GetWeakPtr(),
54 (const ImageDecoder
*) NULL
),
55 base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds
));
58 ~LogoDecoderDelegate() override
{ image_decoder_
->set_delegate(NULL
); }
60 // ImageDecoder::Delegate:
61 void OnImageDecoded(const ImageDecoder
* decoder
,
62 const SkBitmap
& decoded_image
) override
{
63 image_decoded_callback_
.Run(decoded_image
);
67 void OnDecodeImageFailed(const ImageDecoder
* decoder
) override
{
68 image_decoded_callback_
.Run(SkBitmap());
73 scoped_refptr
<ImageDecoder
> image_decoder_
;
74 base::Callback
<void(const SkBitmap
&)> image_decoded_callback_
;
75 base::WeakPtrFactory
<LogoDecoderDelegate
> weak_ptr_factory_
;
77 DISALLOW_COPY_AND_ASSIGN(LogoDecoderDelegate
);
80 class ChromeLogoDelegate
: public search_provider_logos::LogoDelegate
{
82 ChromeLogoDelegate() {}
83 ~ChromeLogoDelegate() override
{}
85 // search_provider_logos::LogoDelegate:
86 void DecodeUntrustedImage(
87 const scoped_refptr
<base::RefCountedString
>& encoded_image
,
88 base::Callback
<void(const SkBitmap
&)> image_decoded_callback
) override
{
89 scoped_refptr
<ImageDecoder
> image_decoder
= new ImageDecoder(
91 encoded_image
->data(),
92 ImageDecoder::DEFAULT_CODEC
);
93 LogoDecoderDelegate
* delegate
=
94 new LogoDecoderDelegate(image_decoder
, image_decoded_callback
);
95 image_decoder
->set_delegate(delegate
);
96 image_decoder
->Start(base::MessageLoopProxy::current());
100 DISALLOW_COPY_AND_ASSIGN(ChromeLogoDelegate
);
105 // LogoService ----------------------------------------------------------------
107 LogoService::LogoService(Profile
* profile
) : profile_(profile
) {
110 LogoService::~LogoService() {
113 void LogoService::GetLogo(search_provider_logos::LogoObserver
* observer
) {
114 TemplateURLService
* template_url_service
=
115 TemplateURLServiceFactory::GetForProfile(profile_
);
116 if (!template_url_service
)
119 TemplateURL
* template_url
= template_url_service
->GetDefaultSearchProvider();
120 if (!template_url
|| !template_url
->url_ref().HasGoogleBaseURLs(
121 template_url_service
->search_terms_data()))
124 if (!logo_tracker_
) {
125 logo_tracker_
.reset(new LogoTracker(
126 profile_
->GetPath().Append(kCachedLogoDirectory
),
127 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
128 BrowserThread::GetBlockingPool(),
129 profile_
->GetRequestContext(),
130 scoped_ptr
<search_provider_logos::LogoDelegate
>(
131 new ChromeLogoDelegate())));
134 logo_tracker_
->SetServerAPI(
135 GetGoogleDoodleURL(profile_
),
136 base::Bind(&search_provider_logos::GoogleParseLogoResponse
),
137 base::Bind(&search_provider_logos::GoogleAppendFingerprintToLogoURL
));
138 logo_tracker_
->GetLogo(observer
);
141 // LogoServiceFactory ---------------------------------------------------------
144 LogoService
* LogoServiceFactory::GetForProfile(Profile
* profile
) {
145 return static_cast<LogoService
*>(
146 GetInstance()->GetServiceForBrowserContext(profile
, true));
150 LogoServiceFactory
* LogoServiceFactory::GetInstance() {
151 return Singleton
<LogoServiceFactory
>::get();
154 LogoServiceFactory::LogoServiceFactory()
155 : BrowserContextKeyedServiceFactory(
157 BrowserContextDependencyManager::GetInstance()) {
160 LogoServiceFactory::~LogoServiceFactory() {}
162 KeyedService
* LogoServiceFactory::BuildServiceInstanceFor(
163 content::BrowserContext
* context
) const {
164 Profile
* profile
= static_cast<Profile
*>(context
);
165 DCHECK(!profile
->IsOffTheRecord());
166 return new LogoService(profile
);