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_url_tracker.h"
13 #include "components/google/core/browser/google_util.h"
14 #include "components/keyed_service/content/browser_context_dependency_manager.h"
15 #include "components/search_engines/template_url_service.h"
16 #include "components/search_provider_logos/google_logo_api.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/url_request/url_request_context_getter.h"
20 using content::BrowserThread
;
21 using search_provider_logos::Logo
;
22 using search_provider_logos::LogoDelegate
;
23 using search_provider_logos::LogoTracker
;
27 const char kGoogleDoodleURLPath
[] = "async/newtab_mobile";
28 const char kCachedLogoDirectory
[] = "Search Logo";
29 const int kDecodeLogoTimeoutSeconds
= 30;
31 // Returns the URL where the doodle can be downloaded, e.g.
32 // https://www.google.com/async/newtab_mobile. This depends on the user's
34 GURL
GetGoogleDoodleURL(Profile
* profile
) {
35 // SetPathStr() requires its argument to stay in scope as long as
36 // |replacements| is, so a std::string is needed, instead of a char*.
37 std::string path
= kGoogleDoodleURLPath
;
38 GURL::Replacements replacements
;
39 replacements
.SetPathStr(path
);
41 GURL
base_url(google_util::CommandLineGoogleBaseURL());
42 if (!base_url
.is_valid())
43 base_url
= google_profile_helper::GetGoogleHomePageURL(profile
);
44 return base_url
.ReplaceComponents(replacements
);
47 class LogoDecoderDelegate
: public ImageDecoder::Delegate
{
50 const scoped_refptr
<ImageDecoder
>& image_decoder
,
51 const base::Callback
<void(const SkBitmap
&)>& image_decoded_callback
)
52 : image_decoder_(image_decoder
),
53 image_decoded_callback_(image_decoded_callback
),
54 weak_ptr_factory_(this) {
55 // If the ImageDecoder crashes or otherwise never completes, call
56 // OnImageDecodeTimedOut() eventually to ensure that image_decoded_callback_
58 base::MessageLoopProxy::current()->PostDelayedTask(
60 base::Bind(&LogoDecoderDelegate::OnDecodeImageFailed
,
61 weak_ptr_factory_
.GetWeakPtr(),
62 (const ImageDecoder
*) NULL
),
63 base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds
));
66 virtual ~LogoDecoderDelegate() {
67 image_decoder_
->set_delegate(NULL
);
70 // ImageDecoder::Delegate:
71 virtual void OnImageDecoded(const ImageDecoder
* decoder
,
72 const SkBitmap
& decoded_image
) OVERRIDE
{
73 image_decoded_callback_
.Run(decoded_image
);
77 virtual void OnDecodeImageFailed(const ImageDecoder
* decoder
) OVERRIDE
{
78 image_decoded_callback_
.Run(SkBitmap());
83 scoped_refptr
<ImageDecoder
> image_decoder_
;
84 base::Callback
<void(const SkBitmap
&)> image_decoded_callback_
;
85 base::WeakPtrFactory
<LogoDecoderDelegate
> weak_ptr_factory_
;
87 DISALLOW_COPY_AND_ASSIGN(LogoDecoderDelegate
);
90 class ChromeLogoDelegate
: public search_provider_logos::LogoDelegate
{
92 ChromeLogoDelegate() {}
93 virtual ~ChromeLogoDelegate() {}
95 // search_provider_logos::LogoDelegate:
96 virtual void DecodeUntrustedImage(
97 const scoped_refptr
<base::RefCountedString
>& encoded_image
,
98 base::Callback
<void(const SkBitmap
&)> image_decoded_callback
) OVERRIDE
{
99 scoped_refptr
<ImageDecoder
> image_decoder
= new ImageDecoder(
101 encoded_image
->data(),
102 ImageDecoder::DEFAULT_CODEC
);
103 LogoDecoderDelegate
* delegate
=
104 new LogoDecoderDelegate(image_decoder
, image_decoded_callback
);
105 image_decoder
->set_delegate(delegate
);
106 image_decoder
->Start(base::MessageLoopProxy::current());
110 DISALLOW_COPY_AND_ASSIGN(ChromeLogoDelegate
);
115 // LogoService ----------------------------------------------------------------
117 LogoService::LogoService(Profile
* profile
) : profile_(profile
) {
120 LogoService::~LogoService() {
123 void LogoService::GetLogo(search_provider_logos::LogoObserver
* observer
) {
124 TemplateURLService
* template_url_service
=
125 TemplateURLServiceFactory::GetForProfile(profile_
);
126 if (!template_url_service
)
129 TemplateURL
* template_url
= template_url_service
->GetDefaultSearchProvider();
130 if (!template_url
|| !template_url
->url_ref().HasGoogleBaseURLs(
131 template_url_service
->search_terms_data()))
134 if (!logo_tracker_
) {
135 logo_tracker_
.reset(new LogoTracker(
136 profile_
->GetPath().Append(kCachedLogoDirectory
),
137 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
138 BrowserThread::GetBlockingPool(),
139 profile_
->GetRequestContext(),
140 scoped_ptr
<search_provider_logos::LogoDelegate
>(
141 new ChromeLogoDelegate())));
144 logo_tracker_
->SetServerAPI(
145 GetGoogleDoodleURL(profile_
),
146 base::Bind(&search_provider_logos::GoogleParseLogoResponse
),
147 base::Bind(&search_provider_logos::GoogleAppendFingerprintToLogoURL
));
148 logo_tracker_
->GetLogo(observer
);
151 // LogoServiceFactory ---------------------------------------------------------
154 LogoService
* LogoServiceFactory::GetForProfile(Profile
* profile
) {
155 return static_cast<LogoService
*>(
156 GetInstance()->GetServiceForBrowserContext(profile
, true));
160 LogoServiceFactory
* LogoServiceFactory::GetInstance() {
161 return Singleton
<LogoServiceFactory
>::get();
164 LogoServiceFactory::LogoServiceFactory()
165 : BrowserContextKeyedServiceFactory(
167 BrowserContextDependencyManager::GetInstance()) {
170 LogoServiceFactory::~LogoServiceFactory() {}
172 KeyedService
* LogoServiceFactory::BuildServiceInstanceFor(
173 content::BrowserContext
* context
) const {
174 Profile
* profile
= static_cast<Profile
*>(context
);
175 DCHECK(!profile
->IsOffTheRecord());
176 return new LogoService(profile
);