// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_ #define COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_ #include <string> #include <vector> #include "base/callback.h" #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/sequenced_task_runner.h" #include "base/time/clock.h" #include "base/time/time.h" #include "components/search_provider_logos/logo_cache.h" #include "components/search_provider_logos/logo_common.h" #include "net/url_request/url_fetcher_delegate.h" #include "url/gurl.h" namespace net { class URLFetcher; class URLRequestContextGetter; } namespace search_provider_logos { // Receives updates when the search provider's logo is available. class LogoObserver { public: virtual ~LogoObserver() {} // Called when the cached logo is available and possibly when a freshly // downloaded logo is available. |logo| will be NULL if no logo is available. // |from_cache| indicates whether the logo was loaded from the cache. // // If the fresh logo is the same as the cached logo, this will not be called // again. virtual void OnLogoAvailable(const Logo* logo, bool from_cache) = 0; // Called when the LogoTracker will no longer send updates to this // LogoObserver. For example: after the cached logo is validated, after // OnFreshLogoAvailable() is called, or when the LogoTracker is destructed. // This is not called when an observer is removed using // LogoTracker::RemoveObserver(). virtual void OnObserverRemoved() = 0; }; // Provides a LogoTracker with methods it needs to download and cache logos. class LogoDelegate { public: virtual ~LogoDelegate() {} // Decodes an untrusted image safely and returns it as an SkBitmap via // |image_decoded_callback|. If image decoding fails, |image_decoded_callback| // should be called with NULL. This will be called on the thread that // LogoTracker lives on and |image_decoded_callback| must be called on the // same thread. virtual void DecodeUntrustedImage( const scoped_refptr<base::RefCountedString>& encoded_image, base::Callback<void(const SkBitmap&)> image_decoded_callback) = 0; }; // Parses the response from the server and returns it as an EncodedLogo. Returns // NULL if the response is invalid. typedef base::Callback< scoped_ptr<EncodedLogo>(const scoped_ptr<std::string>& response, base::Time response_time)> ParseLogoResponse; // Encodes the fingerprint of the cached logo in the logo URL. This enables the // server to verify whether the cached logo is up-to-date. typedef base::Callback< GURL(const GURL& logo_url, const std::string& fingerprint)> AppendFingerprintToLogoURL; // This class provides the logo for a search provider. Logos are downloaded from // the search provider's logo URL and cached on disk. // // Call SetServerAPI() at least once to specify how to get the logo from the // server. Then call GetLogo() to trigger retrieval of the logo and receive // updates once the cached and/or fresh logos are available. class LogoTracker : public net::URLFetcherDelegate { public: // Constructs a LogoTracker with the given LogoDelegate. Takes ownership of // |delegate|, which will be deleted at the same time as the LogoTracker. // // |cached_logo_directory| is the directory in which the cached logo and its // metadata should be saved. // // |file_task_runner| is the SequencedTaskRunner that should be used to run // file system operations. // // |background_task_runner| is the TaskRunner that should be used to for // CPU-intensive background operations. // // |request_context_getter| is the URLRequestContextGetter used to download // the logo. explicit LogoTracker( base::FilePath cached_logo_directory, scoped_refptr<base::SequencedTaskRunner> file_task_runner, scoped_refptr<base::TaskRunner> background_task_runner, scoped_refptr<net::URLRequestContextGetter> request_context_getter, scoped_ptr<LogoDelegate> delegate); virtual ~LogoTracker(); // Defines the server API for downloading and parsing the logo. This must be // called at least once before calling GetLogo(). // // |logo_url| is the URL from which the logo will be downloaded. If |logo_url| // is different than the current logo URL, any pending LogoObservers will be // canceled. // // |parse_logo_response_func| is a callback that will be used to parse the // server's response into a EncodedLogo object. |append_fingerprint_func| is a // callback that will return the URL from which to download the logo if a // cached logo with a fingerprint is already available. Note: // |parse_logo_response_func| and |append_fingerprint_func| must be suitable // for running multiple times, concurrently, and on multiple threads. void SetServerAPI(const GURL& logo_url, const ParseLogoResponse& parse_logo_response_func, const AppendFingerprintToLogoURL& append_fingerprint_func); // Retrieves the current search provider's logo from the local cache and/or // over the network, and registers |observer| to be called when the cached // and/or fresh logos are available. void GetLogo(LogoObserver* observer); // Prevents |observer| from receiving future updates. This is safe to call // even when the observer is being notified of an update. void RemoveObserver(LogoObserver* observer); // Overrides the cache used to store logos. void SetLogoCacheForTests(scoped_ptr<LogoCache> cache); // Overrides the clock used to check the time. void SetClockForTests(scoped_ptr<base::Clock> clock); private: // Cancels the current asynchronous operation, if any, and resets all member // variables that change as the logo is fetched. void ReturnToIdle(); // Called when the cached logo has been read from the cache. |cached_logo| // will be NULL if there wasn't a valid, up-to-date logo in the cache. void OnCachedLogoRead(scoped_ptr<EncodedLogo> cached_logo); // Called when the cached logo has been decoded into an SkBitmap. |image| will // be NULL if decoding failed. void OnCachedLogoAvailable(const LogoMetadata& metadata, const SkBitmap& image); // Stores |logo| in the cache. void SetCachedLogo(scoped_ptr<EncodedLogo> logo); // Updates the metadata for the logo already stored in the cache. void SetCachedMetadata(const LogoMetadata& metadata); // Starts fetching the current logo over the network. void FetchLogo(); // Called when the logo has been downloaded and parsed. |logo| will be NULL // if the server's response was invalid. void OnFreshLogoParsed(scoped_ptr<EncodedLogo> logo); // Called when the fresh logo has been decoded into an SkBitmap. |image| will // be NULL if decoding failed. void OnFreshLogoAvailable(scoped_ptr<EncodedLogo> logo, const SkBitmap& image); // net::URLFetcherDelegate: virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source, int64 current, int64 total) OVERRIDE; // The URL from which the logo is fetched. GURL logo_url_; // The function used to parse the logo response from the server. ParseLogoResponse parse_logo_response_func_; // The function used to include the cached logo's fingerprint in the logo URL. AppendFingerprintToLogoURL append_fingerprint_func_; // False if an asynchronous task is currently running. bool is_idle_; // The logo that's been read from the cache, or NULL if the cache is empty. // Meaningful only if is_cached_logo_valid_ is true; NULL otherwise. scoped_ptr<Logo> cached_logo_; // Whether the value of |cached_logo_| reflects the actual cached logo. // This will be false if the logo hasn't been read from the cache yet. // |cached_logo_| may be NULL even if |is_cached_logo_valid_| is true, if no // logo is cached. bool is_cached_logo_valid_; // The URLFetcher currently fetching the logo. NULL when not fetching. scoped_ptr<net::URLFetcher> fetcher_; // The list of observers to be notified when the logo is available. This // should be empty when the state is IDLE. ObserverList<LogoObserver> logo_observers_; scoped_ptr<LogoDelegate> logo_delegate_; // The cache used to persist the logo on disk. Used only on the file thread. LogoCache* logo_cache_; // Clock used to determine current time. Can be overridden in tests. scoped_ptr<base::Clock> clock_; // The SequencedTaskRunner on which file system operations will be run. scoped_refptr<base::SequencedTaskRunner> file_task_runner_; // The TaskRunner on which the server's response will be parsed. scoped_refptr<base::TaskRunner> background_task_runner_; // The URLRequestContextGetter used for network requests. scoped_refptr<net::URLRequestContextGetter> request_context_getter_; base::WeakPtrFactory<LogoTracker> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(LogoTracker); }; } // namespace search_provider_logos #endif // COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_