Home | History | Annotate | Download | only in android
      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