• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/android/logo_service.h"
6 
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"
19 
20 using content::BrowserThread;
21 using search_provider_logos::Logo;
22 using search_provider_logos::LogoDelegate;
23 using search_provider_logos::LogoTracker;
24 
25 namespace {
26 
27 const char kGoogleDoodleURLPath[] = "async/newtab_mobile";
28 const char kCachedLogoDirectory[] = "Search Logo";
29 const int kDecodeLogoTimeoutSeconds = 30;
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
33 // Google domain.
GetGoogleDoodleURL(Profile * profile)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);
40 
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);
45 }
46 
47 class LogoDecoderDelegate : public ImageDecoder::Delegate {
48  public:
LogoDecoderDelegate(const scoped_refptr<ImageDecoder> & image_decoder,const base::Callback<void (const SkBitmap &)> & image_decoded_callback)49   LogoDecoderDelegate(
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_
57     // is run.
58     base::MessageLoopProxy::current()->PostDelayedTask(
59         FROM_HERE,
60         base::Bind(&LogoDecoderDelegate::OnDecodeImageFailed,
61                    weak_ptr_factory_.GetWeakPtr(),
62                    (const ImageDecoder*) NULL),
63         base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds));
64   }
65 
~LogoDecoderDelegate()66   virtual ~LogoDecoderDelegate() {
67     image_decoder_->set_delegate(NULL);
68   }
69 
70   // ImageDecoder::Delegate:
OnImageDecoded(const ImageDecoder * decoder,const SkBitmap & decoded_image)71   virtual void OnImageDecoded(const ImageDecoder* decoder,
72                               const SkBitmap& decoded_image) OVERRIDE {
73     image_decoded_callback_.Run(decoded_image);
74     delete this;
75   }
76 
OnDecodeImageFailed(const ImageDecoder * decoder)77   virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE {
78     image_decoded_callback_.Run(SkBitmap());
79     delete this;
80   }
81 
82  private:
83   scoped_refptr<ImageDecoder> image_decoder_;
84   base::Callback<void(const SkBitmap&)> image_decoded_callback_;
85   base::WeakPtrFactory<LogoDecoderDelegate> weak_ptr_factory_;
86 
87   DISALLOW_COPY_AND_ASSIGN(LogoDecoderDelegate);
88 };
89 
90 class ChromeLogoDelegate : public search_provider_logos::LogoDelegate {
91  public:
ChromeLogoDelegate()92   ChromeLogoDelegate() {}
~ChromeLogoDelegate()93   virtual ~ChromeLogoDelegate() {}
94 
95   // search_provider_logos::LogoDelegate:
DecodeUntrustedImage(const scoped_refptr<base::RefCountedString> & encoded_image,base::Callback<void (const SkBitmap &)> image_decoded_callback)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(
100         NULL,
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());
107   }
108 
109  private:
110   DISALLOW_COPY_AND_ASSIGN(ChromeLogoDelegate);
111 };
112 
113 }  // namespace
114 
115 // LogoService ----------------------------------------------------------------
116 
LogoService(Profile * profile)117 LogoService::LogoService(Profile* profile) : profile_(profile) {
118 }
119 
~LogoService()120 LogoService::~LogoService() {
121 }
122 
GetLogo(search_provider_logos::LogoObserver * observer)123 void LogoService::GetLogo(search_provider_logos::LogoObserver* observer) {
124   TemplateURLService* template_url_service =
125       TemplateURLServiceFactory::GetForProfile(profile_);
126   if (!template_url_service)
127     return;
128 
129   TemplateURL* template_url = template_url_service->GetDefaultSearchProvider();
130   if (!template_url || !template_url->url_ref().HasGoogleBaseURLs(
131           template_url_service->search_terms_data()))
132     return;
133 
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())));
142   }
143 
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);
149 }
150 
151 // LogoServiceFactory ---------------------------------------------------------
152 
153 // static
GetForProfile(Profile * profile)154 LogoService* LogoServiceFactory::GetForProfile(Profile* profile) {
155   return static_cast<LogoService*>(
156       GetInstance()->GetServiceForBrowserContext(profile, true));
157 }
158 
159 // static
GetInstance()160 LogoServiceFactory* LogoServiceFactory::GetInstance() {
161   return Singleton<LogoServiceFactory>::get();
162 }
163 
LogoServiceFactory()164 LogoServiceFactory::LogoServiceFactory()
165     : BrowserContextKeyedServiceFactory(
166           "LogoService",
167           BrowserContextDependencyManager::GetInstance()) {
168 }
169 
~LogoServiceFactory()170 LogoServiceFactory::~LogoServiceFactory() {}
171 
BuildServiceInstanceFor(content::BrowserContext * context) const172 KeyedService* LogoServiceFactory::BuildServiceInstanceFor(
173     content::BrowserContext* context) const {
174   Profile* profile = static_cast<Profile*>(context);
175   DCHECK(!profile->IsOffTheRecord());
176   return new LogoService(profile);
177 }
178