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