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. 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: 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 66 virtual ~LogoDecoderDelegate() { 67 image_decoder_->set_delegate(NULL); 68 } 69 70 // ImageDecoder::Delegate: 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 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: 92 ChromeLogoDelegate() {} 93 virtual ~ChromeLogoDelegate() {} 94 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( 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 117 LogoService::LogoService(Profile* profile) : profile_(profile) { 118 } 119 120 LogoService::~LogoService() { 121 } 122 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 154 LogoService* LogoServiceFactory::GetForProfile(Profile* profile) { 155 return static_cast<LogoService*>( 156 GetInstance()->GetServiceForBrowserContext(profile, true)); 157 } 158 159 // static 160 LogoServiceFactory* LogoServiceFactory::GetInstance() { 161 return Singleton<LogoServiceFactory>::get(); 162 } 163 164 LogoServiceFactory::LogoServiceFactory() 165 : BrowserContextKeyedServiceFactory( 166 "LogoService", 167 BrowserContextDependencyManager::GetInstance()) { 168 } 169 170 LogoServiceFactory::~LogoServiceFactory() {} 171 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); 177 } 178