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 "base/thread_task_runner_handle.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 "chrome/browser/search_engines/ui_thread_search_terms_data.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 kCachedLogoDirectory
[] = "Search Logo";
27 const int kDecodeLogoTimeoutSeconds
= 30;
29 // Returns the URL where the doodle can be downloaded, e.g.
30 // https://www.google.com/async/newtab_mobile. This depends on the user's
32 GURL
GetGoogleDoodleURL(Profile
* profile
) {
33 GURL
google_base_url(UIThreadSearchTermsData(profile
).GoogleBaseURLValue());
34 const char kGoogleDoodleURLPath
[] = "async/newtab_mobile";
35 GURL::Replacements replacements
;
36 replacements
.SetPathStr(kGoogleDoodleURLPath
);
37 return google_base_url
.ReplaceComponents(replacements
);
40 class LogoDecoderDelegate
: public ImageDecoder::ImageRequest
{
43 const base::Callback
<void(const SkBitmap
&)>& image_decoded_callback
)
44 : image_decoded_callback_(image_decoded_callback
),
45 weak_ptr_factory_(this) {
46 // If the ImageDecoder crashes or otherwise never completes, call
47 // OnImageDecodeTimedOut() eventually to ensure that image_decoded_callback_
49 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
50 FROM_HERE
, base::Bind(&LogoDecoderDelegate::OnDecodeImageFailed
,
51 weak_ptr_factory_
.GetWeakPtr()),
52 base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds
));
55 ~LogoDecoderDelegate() override
{}
57 // ImageDecoder::ImageRequest:
58 void OnImageDecoded(const SkBitmap
& decoded_image
) override
{
59 image_decoded_callback_
.Run(decoded_image
);
63 void OnDecodeImageFailed() override
{
64 image_decoded_callback_
.Run(SkBitmap());
69 base::Callback
<void(const SkBitmap
&)> image_decoded_callback_
;
70 base::WeakPtrFactory
<LogoDecoderDelegate
> weak_ptr_factory_
;
72 DISALLOW_COPY_AND_ASSIGN(LogoDecoderDelegate
);
75 class ChromeLogoDelegate
: public search_provider_logos::LogoDelegate
{
77 ChromeLogoDelegate() {}
78 ~ChromeLogoDelegate() override
{}
80 // search_provider_logos::LogoDelegate:
81 void DecodeUntrustedImage(
82 const scoped_refptr
<base::RefCountedString
>& encoded_image
,
83 base::Callback
<void(const SkBitmap
&)> image_decoded_callback
) override
{
84 LogoDecoderDelegate
* delegate
=
85 new LogoDecoderDelegate(image_decoded_callback
);
86 ImageDecoder::Start(delegate
, encoded_image
->data());
90 DISALLOW_COPY_AND_ASSIGN(ChromeLogoDelegate
);
95 // LogoService ----------------------------------------------------------------
97 LogoService::LogoService(Profile
* profile
) : profile_(profile
) {
100 LogoService::~LogoService() {
103 void LogoService::GetLogo(search_provider_logos::LogoObserver
* observer
) {
104 TemplateURLService
* template_url_service
=
105 TemplateURLServiceFactory::GetForProfile(profile_
);
106 if (!template_url_service
)
109 TemplateURL
* template_url
= template_url_service
->GetDefaultSearchProvider();
110 if (!template_url
|| !template_url
->url_ref().HasGoogleBaseURLs(
111 template_url_service
->search_terms_data()))
114 if (!logo_tracker_
) {
115 logo_tracker_
.reset(new LogoTracker(
116 profile_
->GetPath().Append(kCachedLogoDirectory
),
117 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
118 BrowserThread::GetBlockingPool(),
119 profile_
->GetRequestContext(),
120 scoped_ptr
<search_provider_logos::LogoDelegate
>(
121 new ChromeLogoDelegate())));
124 logo_tracker_
->SetServerAPI(
125 GetGoogleDoodleURL(profile_
),
126 base::Bind(&search_provider_logos::GoogleParseLogoResponse
),
127 base::Bind(&search_provider_logos::GoogleAppendQueryparamsToLogoURL
),
129 logo_tracker_
->GetLogo(observer
);
132 // LogoServiceFactory ---------------------------------------------------------
135 LogoService
* LogoServiceFactory::GetForProfile(Profile
* profile
) {
136 return static_cast<LogoService
*>(
137 GetInstance()->GetServiceForBrowserContext(profile
, true));
141 LogoServiceFactory
* LogoServiceFactory::GetInstance() {
142 return Singleton
<LogoServiceFactory
>::get();
145 LogoServiceFactory::LogoServiceFactory()
146 : BrowserContextKeyedServiceFactory(
148 BrowserContextDependencyManager::GetInstance()) {
151 LogoServiceFactory::~LogoServiceFactory() {}
153 KeyedService
* LogoServiceFactory::BuildServiceInstanceFor(
154 content::BrowserContext
* context
) const {
155 Profile
* profile
= static_cast<Profile
*>(context
);
156 DCHECK(!profile
->IsOffTheRecord());
157 return new LogoService(profile
);